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
|
2025-07-26 23:28:00 +02:00
|
|
|
debugPrint("Spieleliste aktualisiert: " .. (games and table.count(games) or 0) .. " aktive Spiele")
|
2025-07-26 06:21:34 +02:00
|
|
|
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
|
2025-07-26 23:28:00 +02:00
|
|
|
-- Notfall-Fallback Position (anpassen an deine Map)
|
2025-07-26 07:24:05 +02:00
|
|
|
SetEntityCoords(PlayerPedId(), -1042.4, -2745.8, 21.4)
|
2025-07-26 23:28:00 +02:00
|
|
|
debugPrint("WARNUNG: Keine Lobby gefunden, Fallback-Position verwendet!")
|
2025-07-26 07:24:05 +02:00
|
|
|
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
|
|
|
|
2025-07-26 23:28:00 +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
|
2025-07-26 22:42:38 +02:00
|
|
|
debugPrint("WARNUNG: Hit-Event empfangen, aber nicht im TDM!")
|
2025-07-26 22:13:11 +02:00
|
|
|
return
|
|
|
|
end
|
2025-07-26 06:21:34 +02:00
|
|
|
|
2025-07-26 22:13:11 +02:00
|
|
|
if isHit then
|
2025-07-26 22:42:38 +02:00
|
|
|
debugPrint("WARNUNG: Hit-Event empfangen, aber bereits getroffen!")
|
2025-07-26 22:13:11 +02:00
|
|
|
return
|
2025-07-26 06:21:34 +02:00
|
|
|
end
|
|
|
|
|
2025-07-26 22:42:38 +02:00
|
|
|
debugPrint("Spieler wurde getroffen - Starte Respawn-Sequenz")
|
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:42:38 +02:00
|
|
|
-- Verbesserte Respawn-Logik
|
2025-07-26 22:13:11 +02:00
|
|
|
SetTimeout(3000, function()
|
2025-07-26 22:42:38 +02:00
|
|
|
if not inTDM then
|
|
|
|
debugPrint("Respawn abgebrochen - nicht mehr im TDM")
|
|
|
|
return
|
|
|
|
end
|
2025-07-26 21:25:55 +02:00
|
|
|
|
2025-07-26 22:13:11 +02:00
|
|
|
debugPrint("Respawn wird ausgeführt...")
|
|
|
|
|
|
|
|
-- Respawn zum Team Spawn
|
|
|
|
local fieldConfig = Config.gameFields[currentField]
|
|
|
|
if not fieldConfig then
|
2025-07-26 22:42:38 +02:00
|
|
|
debugPrint("FEHLER: Feldkonfiguration nicht gefunden für Respawn!")
|
2025-07-26 22:13:11 +02:00
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local spawnPoints = fieldConfig.teamSpawns[currentTeam]
|
|
|
|
if not spawnPoints or #spawnPoints == 0 then
|
2025-07-26 22:42:38 +02:00
|
|
|
debugPrint("FEHLER: Keine Spawn-Punkte gefunden für Respawn!")
|
2025-07-26 22:13:11 +02:00
|
|
|
return
|
2025-07-26 21:25:55 +02:00
|
|
|
end
|
2025-07-26 22:13:11 +02:00
|
|
|
|
|
|
|
local randomSpawn = spawnPoints[math.random(#spawnPoints)]
|
2025-07-26 22:42:38 +02:00
|
|
|
debugPrint("Respawn-Position: " .. randomSpawn.x .. ", " .. randomSpawn.y .. ", " .. randomSpawn.z)
|
2025-07-26 22:13:11 +02:00
|
|
|
|
|
|
|
-- Teleport zum Spawn mit Fade
|
|
|
|
DoScreenFadeOut(500)
|
|
|
|
Wait(600)
|
|
|
|
|
2025-07-26 22:42:38 +02:00
|
|
|
-- Stellen Sie sicher, dass der Spieler lebt
|
|
|
|
NetworkResurrectLocalPlayer(randomSpawn.x, randomSpawn.y, randomSpawn.z, 0.0, true, false)
|
|
|
|
debugPrint("Spieler wiederbelebt")
|
|
|
|
|
2025-07-26 22:13:11 +02:00
|
|
|
-- Alle Animationen stoppen
|
|
|
|
ClearPedTasksImmediately(ped)
|
|
|
|
|
|
|
|
-- Teleport
|
|
|
|
SetEntityCoords(ped, randomSpawn.x, randomSpawn.y, randomSpawn.z)
|
2025-07-26 22:42:38 +02:00
|
|
|
SetEntityHealth(ped, GetEntityMaxHealth(ped))
|
2025-07-26 22:13:11 +02:00
|
|
|
|
|
|
|
-- Spieler ist wieder aktiv
|
|
|
|
isHit = false
|
2025-07-26 22:42:38 +02:00
|
|
|
debugPrint("Respawn abgeschlossen - Spieler ist wieder aktiv")
|
2025-07-26 22:13:11 +02:00
|
|
|
|
|
|
|
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 23:28:00 +02:00
|
|
|
-- Debug-Ausgabe
|
2025-07-26 22:13:11 +02:00
|
|
|
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
|
|
|
|
})
|
|
|
|
|
2025-07-26 22:42:38 +02:00
|
|
|
-- Spiele einen Sound ab
|
|
|
|
PlaySoundFrontend(-1, "WEAPON_PURCHASE", "HUD_AMMO_SHOP_SOUNDSET", true)
|
|
|
|
|
2025-07-26 06:36:06 +02:00
|
|
|
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 23:28:00 +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()
|
2025-07-26 22:42:38 +02:00
|
|
|
debugPrint("Zeige Hit-Marker an")
|
2025-07-26 07:24:05 +02:00
|
|
|
CreateThread(function()
|
|
|
|
local startTime = GetGameTimer()
|
2025-07-26 22:42:38 +02:00
|
|
|
local duration = 500 -- 500ms display
|
2025-07-26 07:24:05 +02:00
|
|
|
|
2025-07-26 22:42:38 +02:00
|
|
|
while GetGameTimer() - startTime < duration do
|
2025-07-26 07:24:05 +02:00
|
|
|
Wait(0)
|
|
|
|
|
2025-07-26 22:42:38 +02:00
|
|
|
-- Draw hit marker
|
2025-07-26 07:24:05 +02:00
|
|
|
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)
|
|
|
|
|
2025-07-26 22:42:38 +02:00
|
|
|
-- Draw hit text
|
2025-07-26 07:24:05 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2025-07-26 23:28:00 +02:00
|
|
|
if not input then return end
|
2025-07-26 06:21:34 +02:00
|
|
|
|
|
|
|
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 23:28:00 +02:00
|
|
|
-- Verbesserte Damage Handler für korrekte Treffer-Registrierung
|
2025-07-26 06:21:34 +02:00
|
|
|
CreateThread(function()
|
|
|
|
while true do
|
|
|
|
if inTDM and not isHit then
|
|
|
|
local ped = PlayerPedId()
|
|
|
|
|
2025-07-26 23:28:00 +02:00
|
|
|
-- Prüfe, ob der Spieler Schaden genommen hat
|
2025-07-26 06:21:34 +02:00
|
|
|
if HasEntityBeenDamagedByAnyPed(ped) then
|
2025-07-26 22:42:38 +02:00
|
|
|
debugPrint("Schaden erkannt - Identifiziere Angreifer")
|
|
|
|
|
|
|
|
local damager = nil
|
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
|
2025-07-26 22:42:38 +02:00
|
|
|
local playerPed = GetPlayerPed(player)
|
|
|
|
if HasPedBeenDamagedBy(ped, playerPed) then
|
|
|
|
damager = playerPed
|
2025-07-26 22:13:11 +02:00
|
|
|
damagerPlayer = GetPlayerServerId(player)
|
2025-07-26 22:42:38 +02:00
|
|
|
debugPrint("Angreifer identifiziert: " .. damagerPlayer)
|
2025-07-26 22:13:11 +02:00
|
|
|
break
|
2025-07-26 06:36:06 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-07-26 22:42:38 +02:00
|
|
|
-- Schaden zurücksetzen
|
2025-07-26 06:21:34 +02:00
|
|
|
ClearEntityLastDamageEntity(ped)
|
2025-07-26 22:42:38 +02:00
|
|
|
ClearPedLastWeaponDamage(ped)
|
|
|
|
SetEntityHealth(ped, GetEntityMaxHealth(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 23:28:00 +02:00
|
|
|
-- Treffer-Events auslösen
|
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 22:42:38 +02:00
|
|
|
|
|
|
|
-- Warten um mehrfache Auslösung zu verhindern
|
|
|
|
Wait(500)
|
2025-07-26 06:21:34 +02:00
|
|
|
end
|
2025-07-26 22:42:38 +02:00
|
|
|
Wait(0)
|
|
|
|
else
|
|
|
|
Wait(500)
|
2025-07-26 06:21:34 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
|
2025-07-26 23:28:00 +02:00
|
|
|
-- Zusätzlicher Event-Handler für zuverlässigere Treffer-Erkennung
|
|
|
|
AddEventHandler('gameEventTriggered', function(name, args)
|
|
|
|
if name == "CEventNetworkEntityDamage" then
|
|
|
|
local victimId = args[1]
|
|
|
|
local attackerId = args[2]
|
|
|
|
local isDead = args[4] == 1
|
|
|
|
local weaponHash = args[5]
|
|
|
|
|
|
|
|
if inTDM and not isHit and victimId == PlayerPedId() then
|
|
|
|
local attackerServerId = nil
|
|
|
|
|
|
|
|
-- Versuche den Angreifer zu identifizieren
|
|
|
|
for _, player in ipairs(GetActivePlayers()) do
|
|
|
|
if GetPlayerPed(player) == attackerId then
|
|
|
|
attackerServerId = GetPlayerServerId(player)
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
debugPrint("Schaden-Event erkannt: Angreifer=" .. (attackerServerId or "NPC/Unbekannt") .. ", Waffe=" .. weaponHash)
|
|
|
|
|
|
|
|
if attackerServerId then
|
|
|
|
-- Lokale Stats sofort updaten
|
|
|
|
playerStats.deaths = playerStats.deaths + 1
|
|
|
|
|
|
|
|
-- Verhindern, dass der Spieler stirbt
|
|
|
|
SetEntityHealth(PlayerPedId(), GetEntityMaxHealth(PlayerPedId()))
|
|
|
|
|
|
|
|
-- Treffer-Events auslösen
|
|
|
|
TriggerEvent('tdm:playerHit')
|
|
|
|
TriggerServerEvent('tdm:playerWasHit', currentGameId, currentTeam, attackerServerId)
|
|
|
|
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
|
2025-07-26 22:42:38 +02:00
|
|
|
debugPrint("WARNUNG: Feld " .. fieldId .. " hat keine vollständige Lobby-Konfiguration!")
|
2025-07-26 07:24:05 +02:00
|
|
|
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()
|
2025-07-26 22:42:38 +02:00
|
|
|
debugPrint("Aktuelle Werte:")
|
|
|
|
debugPrint("inTDM: " .. tostring(inTDM))
|
|
|
|
debugPrint("currentField: " .. tostring(currentField))
|
|
|
|
debugPrint("currentLobbyField: " .. tostring(currentLobbyField))
|
|
|
|
debugPrint("currentTeam: " .. tostring(currentTeam))
|
|
|
|
debugPrint("currentGameId: " .. tostring(currentGameId))
|
|
|
|
debugPrint("isHit: " .. tostring(isHit))
|
|
|
|
debugPrint("Hits: " .. playerStats.hits)
|
|
|
|
debugPrint("Deaths: " .. playerStats.deaths)
|
|
|
|
|
|
|
|
debugPrint("Verfügbare Felder:")
|
2025-07-26 07:24:05 +02:00
|
|
|
for fieldId, fieldData in pairs(Config.gameFields) do
|
|
|
|
local hasLobby = fieldData.lobby and fieldData.lobby.pos and "✅" or "❌"
|
2025-07-26 22:42:38 +02:00
|
|
|
debugPrint("- " .. fieldId .. ": " .. fieldData.name .. " " .. hasLobby)
|
2025-07-26 07:24:05 +02:00
|
|
|
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 22:42:38 +02:00
|
|
|
NetworkResurrectLocalPlayer(randomSpawn.x, randomSpawn.y, randomSpawn.z, 0.0, true, false)
|
2025-07-26 21:42:05 +02:00
|
|
|
SetEntityCoords(ped, randomSpawn.x, randomSpawn.y, randomSpawn.z)
|
2025-07-26 22:42:38 +02:00
|
|
|
SetEntityHealth(ped, GetEntityMaxHealth(ped))
|
2025-07-26 21:42:05 +02:00
|
|
|
isHit = false
|
|
|
|
|
|
|
|
Wait(100)
|
|
|
|
DoScreenFadeIn(500)
|
|
|
|
|
|
|
|
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
|
2025-07-26 22:42:38 +02:00
|
|
|
debugPrint("Lokale Stats:")
|
|
|
|
debugPrint("Hits: " .. playerStats.hits)
|
|
|
|
debugPrint("Deaths: " .. playerStats.deaths)
|
2025-07-26 22:13:11 +02:00
|
|
|
|
|
|
|
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)
|
2025-07-26 22:42:38 +02:00
|
|
|
|
2025-07-26 23:28:00 +02:00
|
|
|
-- Debug-Befehl zum Testen der Treffer-Registrierung
|
|
|
|
RegisterCommand('testtreffer', function()
|
|
|
|
if inTDM and currentGameId and currentTeam then
|
|
|
|
debugPrint("Teste Treffer-Registrierung")
|
|
|
|
|
|
|
|
-- Simuliere einen Treffer gegen sich selbst
|
2025-07-26 22:42:38 +02:00
|
|
|
local targetTeam = currentTeam == 'team1' and 'team2' or 'team1'
|
2025-07-26 23:28:00 +02:00
|
|
|
TriggerServerEvent('tdm:playerWasHit', currentGameId, currentTeam, GetPlayerServerId(PlayerId()))
|
|
|
|
|
2025-07-26 22:42:38 +02:00
|
|
|
lib.notify({
|
|
|
|
title = 'Debug',
|
2025-07-26 23:28:00 +02:00
|
|
|
description = 'Test-Treffer gesendet!',
|
2025-07-26 22:42:38 +02:00
|
|
|
type = 'info'
|
|
|
|
})
|
|
|
|
else
|
|
|
|
lib.notify({
|
|
|
|
title = 'Debug',
|
|
|
|
description = 'Du musst in einem TDM-Spiel sein!',
|
|
|
|
type = 'error'
|
|
|
|
})
|
|
|
|
end
|
|
|
|
end, false)
|
|
|
|
|
2025-07-26 23:28:00 +02:00
|
|
|
-- Debug-Befehl zum Testen des Respawns
|
|
|
|
RegisterCommand('testrespawn', function()
|
|
|
|
if inTDM then
|
|
|
|
debugPrint("Teste Respawn-Funktion")
|
|
|
|
TriggerEvent('tdm:playerHit')
|
2025-07-26 22:42:38 +02:00
|
|
|
|
2025-07-26 23:28:00 +02:00
|
|
|
lib.notify({
|
|
|
|
title = 'Debug',
|
|
|
|
description = 'Test-Respawn ausgelöst!',
|
|
|
|
type = 'info'
|
|
|
|
})
|
|
|
|
else
|
|
|
|
lib.notify({
|
|
|
|
title = 'Debug',
|
|
|
|
description = 'Du musst in einem TDM-Spiel sein!',
|
|
|
|
type = 'error'
|
|
|
|
})
|
2025-07-26 22:42:38 +02:00
|
|
|
end
|
2025-07-26 23:28:00 +02:00
|
|
|
end, false)
|
|
|
|
|
|
|
|
-- Hilfsfunktion für table.count
|
|
|
|
table.count = function(tbl)
|
|
|
|
local count = 0
|
|
|
|
for _, _ in pairs(tbl) do
|
|
|
|
count = count + 1
|
|
|
|
end
|
|
|
|
return count
|
|
|
|
end
|
|
|
|
|