1
0
Fork 0
forked from Simnation/Main
Main/resources/[standalone]/nordi_tdm/client.lua

913 lines
27 KiB
Lua
Raw Normal View History

2025-07-26 06:21:34 +02:00
local QBCore = exports['qb-core']:GetCoreObject()
local inTDM = false
local currentTeam = nil
local currentGameId = nil
local currentField = nil
2025-07-26 07:24:05 +02:00
local currentLobbyField = nil
local tdmBlips = {}
2025-07-26 06:21:34 +02:00
local teamZoneBlips = {}
local isHit = false
local activeGames = {}
2025-07-26 07:24:05 +02:00
local spawnedNPCs = {}
2025-07-26 06:21:34 +02:00
2025-07-26 06:36:06 +02:00
-- Spieler Statistiken
local playerStats = {
hits = 0,
deaths = 0,
gamesPlayed = 0
}
2025-07-26 22:13:11 +02:00
-- Debug-Funktion für Konsole
local function debugPrint(message)
print("^2[TDM DEBUG]^7 " .. message)
end
2025-07-26 07:24:05 +02:00
-- Events
2025-07-26 06:21:34 +02:00
RegisterNetEvent('tdm:updateGamesList', function(games)
activeGames = games
end)
RegisterNetEvent('tdm:joinGame', function(gameId, team, fieldId)
currentGameId = gameId
currentTeam = team
currentField = fieldId
inTDM = true
isHit = false
2025-07-26 06:36:06 +02:00
-- Stats zurücksetzen
playerStats.hits = 0
playerStats.deaths = 0
playerStats.gamesPlayed = playerStats.gamesPlayed + 1
2025-07-26 06:21:34 +02:00
local fieldConfig = Config.gameFields[fieldId]
-- Teleport zu Team Spawn
local spawnPoints = fieldConfig.teamSpawns[team]
local randomSpawn = spawnPoints[math.random(#spawnPoints)]
SetEntityCoords(PlayerPedId(), randomSpawn.x, randomSpawn.y, randomSpawn.z)
-- Team Maske setzen
setTeamMask(team)
-- Team Zone Blip erstellen
createTeamZoneBlip(team, fieldConfig)
lib.notify({
title = 'TeamDeathmatch',
description = 'Du bist dem Spiel beigetreten! Team: ' .. team,
type = 'success'
})
2025-07-26 22:13:11 +02:00
debugPrint("Spiel beigetreten: " .. gameId .. ", Team: " .. team .. ", Feld: " .. fieldId)
2025-07-26 06:21:34 +02:00
end)
RegisterNetEvent('tdm:leaveGame', function()
inTDM = false
2025-07-26 07:01:07 +02:00
local previousField = currentField
2025-07-26 06:21:34 +02:00
currentTeam = nil
currentGameId = nil
currentField = nil
isHit = false
2025-07-26 07:24:05 +02:00
-- Sichere Rückkehr zur Lobby
local lobbyPos = nil
-- Versuche zuerst die vorherige Feld-Lobby
if previousField and Config.gameFields[previousField] and Config.gameFields[previousField].lobby then
lobbyPos = Config.gameFields[previousField].lobby.pos
-- Dann die aktuelle Lobby-Feld
elseif currentLobbyField and Config.gameFields[currentLobbyField] and Config.gameFields[currentLobbyField].lobby then
lobbyPos = Config.gameFields[currentLobbyField].lobby.pos
-- Fallback zur ersten verfügbaren Lobby
2025-07-26 07:01:07 +02:00
else
2025-07-26 07:24:05 +02:00
for fieldId, fieldData in pairs(Config.gameFields) do
if fieldData.lobby and fieldData.lobby.pos then
lobbyPos = fieldData.lobby.pos
break
end
2025-07-26 07:01:07 +02:00
end
end
2025-07-26 06:21:34 +02:00
2025-07-26 07:24:05 +02:00
-- Teleport zur Lobby (mit Fallback-Position)
if lobbyPos then
SetEntityCoords(PlayerPedId(), lobbyPos.x, lobbyPos.y, lobbyPos.z)
else
-- Notfall-Fallback Position (anpassen an deine Map)
SetEntityCoords(PlayerPedId(), -1042.4, -2745.8, 21.4)
print("^3[TDM WARNING]^7 Keine Lobby gefunden, Fallback-Position verwendet!")
end
2025-07-26 06:21:34 +02:00
-- Maske entfernen
SetPedComponentVariation(PlayerPedId(), 1, 0, 0, 0)
-- Zone Blips entfernen
removeTeamZoneBlips()
2025-07-26 06:36:06 +02:00
lib.hideTextUI()
2025-07-26 06:21:34 +02:00
lib.notify({
title = 'TeamDeathmatch',
description = 'Du hast das Spiel verlassen!',
type = 'error'
})
2025-07-26 22:13:11 +02:00
debugPrint("Spiel verlassen")
2025-07-26 06:21:34 +02:00
end)
RegisterNetEvent('tdm:joinRequest', function(gameId, playerName, playerId)
local alert = lib.alertDialog({
header = 'Join Anfrage',
content = playerName .. ' möchte deinem Spiel beitreten.\n\nErlauben?',
centered = true,
cancel = true,
labels = {
cancel = 'Ablehnen',
confirm = 'Erlauben'
}
})
if alert == 'confirm' then
TriggerServerEvent('tdm:approveJoinRequest', gameId, playerId, true)
else
TriggerServerEvent('tdm:approveJoinRequest', gameId, playerId, false)
end
end)
RegisterNetEvent('tdm:joinRequestResult', function(approved, gameName)
if approved then
lib.notify({
title = 'TeamDeathmatch',
description = 'Deine Anfrage wurde angenommen!',
type = 'success'
})
else
lib.notify({
title = 'TeamDeathmatch',
description = 'Deine Anfrage für "' .. gameName .. '" wurde abgelehnt!',
type = 'error'
})
end
end)
RegisterNetEvent('tdm:playerHit', function()
2025-07-26 22:13:11 +02:00
if not inTDM then
print("^3[TDM WARNING]^7 Hit-Event empfangen, aber nicht im TDM!")
return
end
2025-07-26 06:21:34 +02:00
2025-07-26 22:13:11 +02:00
if isHit then
print("^3[TDM WARNING]^7 Hit-Event empfangen, aber bereits getroffen!")
return
2025-07-26 06:21:34 +02:00
end
2025-07-26 22:13:11 +02:00
isHit = true
local ped = PlayerPedId()
2025-07-26 06:21:34 +02:00
2025-07-26 22:13:11 +02:00
-- Benachrichtigung
2025-07-26 06:21:34 +02:00
lib.notify({
title = 'TeamDeathmatch',
2025-07-26 21:25:55 +02:00
description = 'Du wurdest getroffen! Respawn in 3 Sekunden...',
2025-07-26 06:21:34 +02:00
type = 'error'
})
2025-07-26 22:13:11 +02:00
-- Vereinfachter Respawn ohne Animation
SetTimeout(3000, function()
if not inTDM then return end
2025-07-26 21:25:55 +02:00
2025-07-26 22:13:11 +02:00
-- Debug-Nachricht
debugPrint("Respawn wird ausgeführt...")
-- Respawn zum Team Spawn
local fieldConfig = Config.gameFields[currentField]
if not fieldConfig then
print("^1[TDM ERROR]^7 Feldkonfiguration nicht gefunden!")
return
end
local spawnPoints = fieldConfig.teamSpawns[currentTeam]
if not spawnPoints or #spawnPoints == 0 then
print("^1[TDM ERROR]^7 Keine Spawn-Punkte gefunden!")
return
2025-07-26 21:25:55 +02:00
end
2025-07-26 22:13:11 +02:00
local randomSpawn = spawnPoints[math.random(#spawnPoints)]
-- Teleport zum Spawn mit Fade
DoScreenFadeOut(500)
Wait(600)
-- Alle Animationen stoppen
ClearPedTasksImmediately(ped)
-- Teleport
SetEntityCoords(ped, randomSpawn.x, randomSpawn.y, randomSpawn.z)
-- Spieler ist wieder aktiv
isHit = false
Wait(100)
DoScreenFadeIn(500)
lib.notify({
title = 'TeamDeathmatch',
description = 'Du bist wieder im Spiel!',
type = 'success'
})
2025-07-26 21:25:55 +02:00
end)
2025-07-26 06:21:34 +02:00
end)
2025-07-26 06:36:06 +02:00
RegisterNetEvent('tdm:updateScore', function(team1Score, team2Score, gameStats)
2025-07-26 22:13:11 +02:00
-- Debug-Ausgabe
debugPrint("Score Update empfangen: Team1=" .. team1Score .. ", Team2=" .. team2Score)
if gameStats then
debugPrint("GameStats: Hits=" .. (gameStats.hits or "nil") .. ", Deaths=" .. (gameStats.deaths or "nil"))
end
2025-07-26 21:25:55 +02:00
-- Verwende gameStats falls verfügbar, sonst lokale Stats
local myHits = gameStats and gameStats.hits or playerStats.hits
local myDeaths = gameStats and gameStats.deaths or playerStats.deaths
2025-07-26 06:36:06 +02:00
local displayText = string.format(
'[Team 1: %d] VS [Team 2: %d] | Deine Treffer: %d | Tode: %d',
team1Score,
team2Score,
2025-07-26 21:25:55 +02:00
myHits,
myDeaths
2025-07-26 06:36:06 +02:00
)
lib.showTextUI(displayText, {
2025-07-26 06:21:34 +02:00
position = "top-center",
icon = 'crosshairs'
})
end)
2025-07-26 06:36:06 +02:00
RegisterNetEvent('tdm:hitRegistered', function()
playerStats.hits = playerStats.hits + 1
lib.notify({
title = 'Treffer!',
description = 'Du hast einen Gegner getroffen! (+1 Punkt)',
type = 'success',
duration = 2000
})
showHitMarker()
2025-07-26 21:25:55 +02:00
-- Score sofort aktualisieren
2025-07-26 22:13:11 +02:00
if currentGameId then
TriggerServerEvent('tdm:requestScoreUpdate', currentGameId)
end
debugPrint("Treffer registriert! Neue Hits: " .. playerStats.hits)
2025-07-26 06:36:06 +02:00
end)
RegisterNetEvent('tdm:deathRegistered', function()
playerStats.deaths = playerStats.deaths + 1
2025-07-26 21:25:55 +02:00
-- Score sofort aktualisieren
2025-07-26 22:13:11 +02:00
if currentGameId then
TriggerServerEvent('tdm:requestScoreUpdate', currentGameId)
end
debugPrint("Tod registriert! Neue Deaths: " .. playerStats.deaths)
2025-07-26 06:36:06 +02:00
end)
2025-07-26 06:21:34 +02:00
RegisterNetEvent('tdm:gameEnded', function(winnerTeam, team1Score, team2Score)
lib.hideTextUI()
2025-07-26 06:36:06 +02:00
local wonGame = (currentTeam == 'team1' and winnerTeam == 'team1') or (currentTeam == 'team2' and winnerTeam == 'team2')
local resultText = wonGame and '🏆 GEWONNEN!' or '💀 VERLOREN!'
local statsText = string.format(
'%s\n\n' ..
'Endergebnis:\n' ..
'Team 1: %d Punkte\n' ..
'Team 2: %d Punkte\n\n' ..
'Deine Statistiken:\n' ..
'🎯 Treffer: %d\n' ..
'💀 Tode: %d\n' ..
'📊 K/D: %.2f',
resultText,
team1Score,
team2Score,
playerStats.hits,
playerStats.deaths,
playerStats.deaths > 0 and (playerStats.hits / playerStats.deaths) or playerStats.hits
)
2025-07-26 06:21:34 +02:00
local alert = lib.alertDialog({
header = 'Spiel beendet!',
2025-07-26 06:36:06 +02:00
content = statsText,
2025-07-26 06:21:34 +02:00
centered = true,
cancel = false
})
Wait(5000)
TriggerServerEvent('tdm:leaveGame')
2025-07-26 22:13:11 +02:00
debugPrint("Spiel beendet! Gewinner: " .. (winnerTeam or "Unentschieden"))
2025-07-26 06:21:34 +02:00
end)
2025-07-26 07:24:05 +02:00
-- Funktionen
2025-07-26 06:21:34 +02:00
function setTeamMask(team)
local ped = PlayerPedId()
local maskData = Config.teamMasks[team]
if maskData then
2025-07-26 07:01:07 +02:00
-- Geschlecht des Spielers ermitteln
local playerGender = GetEntityModel(ped) == GetHashKey("mp_f_freemode_01") and "female" or "male"
-- Entsprechende Maske setzen
local genderMask = maskData[playerGender]
if genderMask then
SetPedComponentVariation(ped, genderMask.component, genderMask.drawable, genderMask.texture, 0)
2025-07-26 22:13:11 +02:00
debugPrint("Maske gesetzt: " .. team .. " (" .. playerGender .. ")")
else
debugPrint("Keine Maske für " .. team .. " (" .. playerGender .. ") gefunden!")
2025-07-26 07:01:07 +02:00
end
2025-07-26 22:13:11 +02:00
else
debugPrint("Keine Masken-Daten für Team " .. team .. " gefunden!")
2025-07-26 06:21:34 +02:00
end
end
2025-07-26 07:24:05 +02:00
function createTeamZoneBlip(team, fieldConfig)
local zone = fieldConfig.teamZones[team]
2025-07-26 06:21:34 +02:00
2025-07-26 07:24:05 +02:00
local blip = AddBlipForRadius(zone.center.x, zone.center.y, zone.center.z, zone.radius)
SetBlipHighDetail(blip, true)
SetBlipColour(blip, team == 'team1' and 1 or 3)
SetBlipAlpha(blip, 128)
teamZoneBlips[team] = blip
2025-07-26 22:13:11 +02:00
debugPrint("Team Zone Blip erstellt für " .. team)
2025-07-26 06:21:34 +02:00
end
2025-07-26 07:24:05 +02:00
function removeTeamZoneBlips()
for team, blip in pairs(teamZoneBlips) do
if DoesBlipExist(blip) then
RemoveBlip(blip)
2025-07-26 06:36:06 +02:00
end
2025-07-26 07:01:07 +02:00
end
2025-07-26 07:24:05 +02:00
teamZoneBlips = {}
2025-07-26 22:13:11 +02:00
debugPrint("Team Zone Blips entfernt")
2025-07-26 07:24:05 +02:00
end
function highlightTeamZone(team)
if teamZoneBlips[team] and DoesBlipExist(teamZoneBlips[team]) then
SetBlipFlashes(teamZoneBlips[team], true)
2025-07-26 07:01:07 +02:00
end
2025-07-26 06:36:06 +02:00
end
2025-07-26 07:24:05 +02:00
function showHitMarker()
CreateThread(function()
local startTime = GetGameTimer()
while GetGameTimer() - startTime < 500 do
Wait(0)
DrawRect(0.5, 0.5, 0.02, 0.002, 255, 0, 0, 255)
DrawRect(0.5, 0.5, 0.002, 0.02, 255, 0, 0, 255)
SetTextFont(4)
SetTextProportional(1)
SetTextScale(0.5, 0.5)
SetTextColour(255, 0, 0, 255)
SetTextEntry("STRING")
AddTextComponentString("TREFFER!")
SetTextCentre(true)
DrawText(0.5, 0.45)
end
end)
end
2025-07-26 07:01:07 +02:00
function openMainMenu(fieldId)
2025-07-26 07:24:05 +02:00
-- Sicherheitscheck
if not fieldId or not Config.gameFields[fieldId] then
lib.notify({
title = 'Fehler',
description = 'Ungültiges Spielfeld!',
type = 'error'
})
return
end
currentLobbyField = fieldId
2025-07-26 06:21:34 +02:00
TriggerServerEvent('tdm:requestGamesList')
2025-07-26 06:36:06 +02:00
Wait(100)
2025-07-26 06:21:34 +02:00
2025-07-26 07:01:07 +02:00
local fieldName = Config.gameFields[fieldId].name
2025-07-26 06:21:34 +02:00
local options = {
{
title = 'Neues Spiel erstellen',
2025-07-26 07:01:07 +02:00
description = 'Erstelle ein neues Spiel für ' .. fieldName,
2025-07-26 06:21:34 +02:00
icon = 'plus',
onSelect = function()
2025-07-26 07:01:07 +02:00
openCreateGameMenu(fieldId)
2025-07-26 06:21:34 +02:00
end
},
{
title = 'Spiel beitreten',
description = 'Trete einem laufenden Spiel bei',
icon = 'users',
onSelect = function()
2025-07-26 07:01:07 +02:00
openJoinGameMenu(fieldId)
2025-07-26 06:21:34 +02:00
end
}
}
if inTDM then
table.insert(options, {
title = 'Aktuelles Spiel verlassen',
description = 'Verlasse das laufende Spiel',
icon = 'door-open',
iconColor = 'red',
onSelect = function()
TriggerServerEvent('tdm:leaveGame')
end
})
end
lib.registerContext({
2025-07-26 07:01:07 +02:00
id = 'tdm_main_menu_' .. fieldId,
title = 'TeamDeathmatch - ' .. fieldName,
2025-07-26 06:21:34 +02:00
options = options
})
2025-07-26 07:01:07 +02:00
lib.showContext('tdm_main_menu_' .. fieldId)
2025-07-26 06:21:34 +02:00
end
2025-07-26 07:01:07 +02:00
function openCreateGameMenu(fieldId)
2025-07-26 07:24:05 +02:00
if not fieldId or not Config.gameFields[fieldId] then
lib.notify({
title = 'Fehler',
description = 'Ungültiges Spielfeld!',
type = 'error'
})
return
end
2025-07-26 07:01:07 +02:00
local fieldData = Config.gameFields[fieldId]
2025-07-26 06:21:34 +02:00
2025-07-26 07:01:07 +02:00
local input = lib.inputDialog('Neues Spiel erstellen - ' .. fieldData.name, {
2025-07-26 06:21:34 +02:00
{
type = 'input',
label = 'Spiel Name',
description = 'Gib deinem Spiel einen Namen',
required = true,
max = 30
},
{
type = 'select',
label = 'Spiel Typ',
description = 'Wähle den Spiel Typ',
required = true,
options = {
{value = 'public', label = 'Öffentlich (Jeder kann beitreten)'},
{value = 'private', label = 'Privat (Nur mit Genehmigung)'}
}
},
{
type = 'input',
label = 'Passwort (Optional)',
description = 'Passwort für das Spiel (leer lassen für kein Passwort)',
password = true
}
})
if not input then return end
local gameName = input[1]
2025-07-26 07:01:07 +02:00
local gameType = input[2]
local password = input[3] and input[3] ~= '' and input[3] or nil
2025-07-26 06:21:34 +02:00
2025-07-26 07:01:07 +02:00
if gameName and gameType then
2025-07-26 06:21:34 +02:00
TriggerServerEvent('tdm:createGame', gameName, fieldId, gameType, password)
end
end
2025-07-26 07:01:07 +02:00
function openJoinGameMenu(fieldId)
2025-07-26 07:24:05 +02:00
if not fieldId or not Config.gameFields[fieldId] then
lib.notify({
title = 'Fehler',
description = 'Ungültiges Spielfeld!',
type = 'error'
})
return
end
2025-07-26 22:13:11 +02:00
2025-07-26 06:21:34 +02:00
TriggerServerEvent('tdm:requestGamesList')
Wait(200)
local options = {}
2025-07-26 07:01:07 +02:00
local fieldName = Config.gameFields[fieldId].name
2025-07-26 06:21:34 +02:00
2025-07-26 07:01:07 +02:00
-- Nur Spiele für dieses Feld anzeigen
2025-07-26 06:21:34 +02:00
for gameId, gameData in pairs(activeGames) do
2025-07-26 07:01:07 +02:00
if gameData.fieldId == fieldId then
local playerCount = #gameData.team1 + #gameData.team2
local maxPlayers = Config.gameFields[gameData.fieldId].maxPlayers
local statusText = gameData.status == 'waiting' and 'Wartend' or 'Läuft'
local typeText = gameData.gameType == 'public' and '🌐 Öffentlich' or '🔒 Privat'
local passwordIcon = gameData.hasPassword and ' 🔑' or ''
table.insert(options, {
title = gameData.name .. passwordIcon,
description = typeText .. ' | Spieler: ' .. playerCount .. '/' .. maxPlayers .. ' | Status: ' .. statusText,
icon = gameData.gameType == 'public' and 'globe' or 'lock',
iconColor = gameData.gameType == 'public' and 'green' or 'orange',
args = {
gameId = gameId,
hasPassword = gameData.hasPassword,
gameType = gameData.gameType
},
onSelect = function(args)
if args.hasPassword then
local input = lib.inputDialog('Passwort eingeben', {
{
type = 'input',
label = 'Passwort',
description = 'Gib das Spiel-Passwort ein',
required = true,
password = true
}
})
if input and input[1] then
TriggerServerEvent('tdm:requestJoinGame', args.gameId, input[1])
end
else
TriggerServerEvent('tdm:requestJoinGame', args.gameId)
2025-07-26 06:21:34 +02:00
end
end
2025-07-26 07:01:07 +02:00
})
end
2025-07-26 06:21:34 +02:00
end
if #options == 0 then
table.insert(options, {
title = 'Keine Spiele verfügbar',
2025-07-26 07:01:07 +02:00
description = 'Erstelle ein neues Spiel für ' .. fieldName,
2025-07-26 06:21:34 +02:00
icon = 'info',
disabled = true
})
end
lib.registerContext({
2025-07-26 07:01:07 +02:00
id = 'tdm_join_menu_' .. fieldId,
title = 'Spiel beitreten - ' .. fieldName,
menu = 'tdm_main_menu_' .. fieldId,
2025-07-26 06:21:34 +02:00
options = options
})
2025-07-26 07:01:07 +02:00
lib.showContext('tdm_join_menu_' .. fieldId)
2025-07-26 06:21:34 +02:00
end
2025-07-26 07:24:05 +02:00
-- Zone Marker Renderer
2025-07-26 06:21:34 +02:00
CreateThread(function()
while true do
Wait(0)
if inTDM and currentTeam and currentField then
local zone = Config.gameFields[currentField].teamZones[currentTeam]
local color = zone.color
DrawMarker(
1,
zone.center.x, zone.center.y, zone.center.z - 1.0,
0.0, 0.0, 0.0,
0.0, 0.0, 0.0,
zone.radius * 2, zone.radius * 2, 1.0,
color.r, color.g, color.b, color.a,
false, true, 2, false, nil, nil, false
)
if isHit then
DrawMarker(
2,
zone.center.x, zone.center.y, zone.center.z + 5.0,
0.0, 0.0, 0.0,
0.0, 0.0, 0.0,
1.0, 1.0, 1.0,
255, 255, 0, 200,
true, true, 2, false, nil, nil, false
)
end
else
Wait(1000)
end
end
end)
2025-07-26 21:25:55 +02:00
-- Damage Handler (erweitert)
2025-07-26 06:21:34 +02:00
CreateThread(function()
while true do
Wait(100)
if inTDM and not isHit then
local ped = PlayerPedId()
if HasEntityBeenDamagedByAnyPed(ped) then
2025-07-26 22:13:11 +02:00
local damager = GetPedSourceOfDeath(ped)
2025-07-26 06:36:06 +02:00
local damagerPlayer = nil
2025-07-26 21:42:05 +02:00
-- Versuche den Angreifer zu identifizieren
2025-07-26 22:13:11 +02:00
for _, player in ipairs(GetActivePlayers()) do
if GetPlayerPed(player) == damager then
damagerPlayer = GetPlayerServerId(player)
break
2025-07-26 06:36:06 +02:00
end
end
2025-07-26 06:21:34 +02:00
ClearEntityLastDamageEntity(ped)
2025-07-26 21:25:55 +02:00
-- Lokale Stats sofort updaten
playerStats.deaths = playerStats.deaths + 1
2025-07-26 22:13:11 +02:00
debugPrint("Getroffen von: " .. (damagerPlayer or "Unbekannt"))
2025-07-26 06:21:34 +02:00
TriggerEvent('tdm:playerHit')
2025-07-26 06:36:06 +02:00
TriggerServerEvent('tdm:playerWasHit', currentGameId, currentTeam, damagerPlayer)
2025-07-26 06:21:34 +02:00
end
end
end
end)
2025-07-26 07:24:05 +02:00
-- Death Handler
2025-07-26 06:21:34 +02:00
CreateThread(function()
while true do
Wait(1000)
if inTDM then
local ped = PlayerPedId()
if IsEntityDead(ped) then
2025-07-26 22:13:11 +02:00
debugPrint("Spieler ist tot!")
2025-07-26 06:21:34 +02:00
TriggerServerEvent('tdm:playerDied', currentGameId)
lib.notify({
title = 'TeamDeathmatch',
description = 'Du bist ausgeschieden!',
type = 'error'
})
Wait(3000)
TriggerServerEvent('tdm:leaveGame')
end
end
end
end)
2025-07-26 07:24:05 +02:00
-- NPC Setup für alle Felder
2025-07-26 06:21:34 +02:00
CreateThread(function()
2025-07-26 07:01:07 +02:00
-- Für jedes Spielfeld Blip und NPC erstellen
for fieldId, fieldData in pairs(Config.gameFields) do
2025-07-26 07:24:05 +02:00
if fieldData.lobby and fieldData.lobby.pos and fieldData.lobby.npc then
local lobbyPos = fieldData.lobby.pos
local npcData = fieldData.lobby.npc
-- Blip erstellen
local blip = AddBlipForCoord(lobbyPos.x, lobbyPos.y, lobbyPos.z)
SetBlipSprite(blip, 432)
SetBlipDisplay(blip, 4)
SetBlipScale(blip, 0.8)
SetBlipColour(blip, 1)
SetBlipAsShortRange(blip, true)
BeginTextCommandSetBlipName("STRING")
AddTextComponentString("TDM - " .. fieldData.name)
EndTextCommandSetBlipName(blip)
tdmBlips[fieldId] = blip
-- NPC erstellen
RequestModel(GetHashKey(npcData.model))
while not HasModelLoaded(GetHashKey(npcData.model)) do
Wait(1)
end
local npc = CreatePed(4, GetHashKey(npcData.model), npcData.coords.x, npcData.coords.y, npcData.coords.z, npcData.coords.w, false, true)
SetEntityInvincible(npc, true)
FreezeEntityPosition(npc, true)
SetBlockingOfNonTemporaryEvents(npc, true)
spawnedNPCs[fieldId] = npc
-- Target für diesen NPC
exports['qb-target']:AddTargetEntity(npc, {
options = {
{
type = "client",
event = "tdm:openFieldMenu",
icon = "fas fa-crosshairs",
label = "TeamDeathmatch - " .. fieldData.name,
fieldId = fieldId
},
2025-07-26 07:01:07 +02:00
},
2025-07-26 07:24:05 +02:00
distance = 2.5
})
2025-07-26 22:13:11 +02:00
debugPrint("NPC und Blip für Feld " .. fieldId .. " erstellt")
2025-07-26 07:24:05 +02:00
else
print("^3[TDM WARNING]^7 Feld " .. fieldId .. " hat keine vollständige Lobby-Konfiguration!")
end
2025-07-26 06:21:34 +02:00
end
end)
2025-07-26 07:01:07 +02:00
-- Event für Feld-spezifisches Menü
RegisterNetEvent('tdm:openFieldMenu', function(data)
2025-07-26 07:24:05 +02:00
if data and data.fieldId then
openMainMenu(data.fieldId)
else
lib.notify({
title = 'Fehler',
description = 'Keine Feld-ID übertragen!',
type = 'error'
})
end
2025-07-26 06:21:34 +02:00
end)
2025-07-26 07:01:07 +02:00
-- Chat Command zum Spiel verlassen
RegisterCommand('leavetdm', function()
if inTDM then
TriggerServerEvent('tdm:leaveGame')
lib.notify({
title = 'TeamDeathmatch',
description = 'Du hast das Spiel über Command verlassen!',
type = 'info'
})
else
lib.notify({
title = 'TeamDeathmatch',
description = 'Du bist in keinem Spiel!',
type = 'error'
})
end
end, false)
-- Keybind zum Spiel verlassen
RegisterKeyMapping('leavetdm', 'TeamDeathmatch verlassen', 'keyboard', 'F7')
2025-07-26 07:24:05 +02:00
-- Debug Command zum Testen der Config
RegisterCommand('debugtdm', function()
print("^2[TDM DEBUG]^7 Aktuelle Werte:")
print("inTDM: " .. tostring(inTDM))
print("currentField: " .. tostring(currentField))
print("currentLobbyField: " .. tostring(currentLobbyField))
print("currentTeam: " .. tostring(currentTeam))
2025-07-26 22:13:11 +02:00
print("currentGameId: " .. tostring(currentGameId))
print("isHit: " .. tostring(isHit))
print("Hits: " .. playerStats.hits)
print("Deaths: " .. playerStats.deaths)
2025-07-26 07:24:05 +02:00
print("^2[TDM DEBUG]^7 Verfügbare Felder:")
for fieldId, fieldData in pairs(Config.gameFields) do
local hasLobby = fieldData.lobby and fieldData.lobby.pos and "" or ""
print("- " .. fieldId .. ": " .. fieldData.name .. " " .. hasLobby)
end
end, false)
-- Debug Commands für Masken
RegisterCommand('testmask', function(source, args)
if not args[1] or not args[2] then
lib.notify({
title = 'Debug',
description = 'Verwendung: /testmask [team1/team2] [male/female]',
type = 'error'
})
return
end
local team = args[1]
local gender = args[2]
if Config.teamMasks[team] and Config.teamMasks[team][gender] then
local maskData = Config.teamMasks[team][gender]
local ped = PlayerPedId()
SetPedComponentVariation(ped, maskData.component, maskData.drawable, maskData.texture, 0)
lib.notify({
title = 'Debug',
description = 'Maske gesetzt: ' .. team .. ' (' .. gender .. ')',
type = 'success'
})
else
lib.notify({
title = 'Debug',
description = 'Maske nicht gefunden!',
type = 'error'
})
end
end, false)
-- Command zum Entfernen der Maske
RegisterCommand('removemask', function()
SetPedComponentVariation(PlayerPedId(), 1, 0, 0, 0)
lib.notify({
title = 'Debug',
description = 'Maske entfernt!',
type = 'info'
})
end, false)
2025-07-26 21:42:05 +02:00
-- Debug-Funktion für Respawn
RegisterCommand('forcetdmrespawn', function()
if inTDM and currentTeam and currentField then
local ped = PlayerPedId()
local fieldConfig = Config.gameFields[currentField]
local spawnPoints = fieldConfig.teamSpawns[currentTeam]
local randomSpawn = spawnPoints[math.random(#spawnPoints)]
DoScreenFadeOut(500)
2025-07-26 22:13:11 +02:00
Wait(600)
2025-07-26 21:42:05 +02:00
2025-07-26 22:13:11 +02:00
ClearPedTasksImmediately(ped)
2025-07-26 21:42:05 +02:00
SetEntityCoords(ped, randomSpawn.x, randomSpawn.y, randomSpawn.z)
isHit = false
Wait(100)
DoScreenFadeIn(500)
2025-07-26 22:13:11 +02:00
lib.notify({
title = 'Debug',
description = 'Manueller Respawn durchgeführt
2025-07-26 21:42:05 +02:00
lib.notify({
title = 'Debug',
description = 'Manueller Respawn durchgeführt!',
type = 'success'
})
else
lib.notify({
title = 'Debug',
description = 'Du bist nicht in einem TDM-Spiel!',
type = 'error'
})
end
end, false)
2025-07-26 22:13:11 +02:00
-- Debug-Funktion für Stats
RegisterCommand('showstats', function()
if inTDM then
print("^2[TDM DEBUG]^7 Lokale Stats:")
print("Hits: " .. playerStats.hits)
print("Deaths: " .. playerStats.deaths)
if currentGameId then
TriggerServerEvent('tdm:debugPlayerStats', currentGameId)
end
lib.notify({
title = 'Debug',
description = 'Lokale Stats - Hits: ' .. playerStats.hits .. ', Deaths: ' .. playerStats.deaths,
type = 'info'
})
else
lib.notify({
title = 'Debug',
description = 'Du bist nicht in einem TDM-Spiel!',
type = 'error'
})
end
end, false)
-- Debug-Funktion für manuellen Hit
RegisterCommand('testhit', function()
if inTDM then
TriggerEvent('tdm:playerHit')
lib.notify({
title = 'Debug',
description = 'Test-Hit ausgelöst!',
type = 'info'
})
else
lib.notify({
title = 'Debug',
description = 'Du bist nicht in einem TDM-Spiel!',
type = 'error'
})
end
end, false)
-- Debug-Funktion für manuellen Treffer
RegisterCommand('testtreff', function()
if inTDM then
TriggerEvent('tdm:hitRegistered')
lib.notify({
title = 'Debug',
description = 'Test-Treffer registriert!',
type = 'info'
})
else
lib.notify({
title = 'Debug',
description = 'Du bist nicht in einem TDM-Spiel!',
type = 'error'
})
end
end, false)