diff --git a/resources/[standalone]/nordi_tdm/client.lua b/resources/[standalone]/nordi_tdm/client.lua index 6b14d8a89..04211cd27 100644 --- a/resources/[standalone]/nordi_tdm/client.lua +++ b/resources/[standalone]/nordi_tdm/client.lua @@ -3,12 +3,12 @@ local inTDM = false local currentTeam = nil local currentGameId = nil local currentField = nil -local currentLobbyField = nil -- Neue Variable für aktuelle Lobby -local tdmBlips = {} -- Mehrere Blips +local currentLobbyField = nil +local tdmBlips = {} local teamZoneBlips = {} local isHit = false local activeGames = {} -local spawnedNPCs = {} -- Gespawnte NPCs verwalten +local spawnedNPCs = {} -- Spieler Statistiken local playerStats = { @@ -17,7 +17,7 @@ local playerStats = { gamesPlayed = 0 } --- Events (gleich wie vorher, nur leaveGame angepasst) +-- Events RegisterNetEvent('tdm:updateGamesList', function(games) activeGames = games end) @@ -63,21 +63,32 @@ RegisterNetEvent('tdm:leaveGame', function() currentField = nil isHit = false - -- Zurück zur entsprechenden Lobby (falls vorher in einem Spiel) - if previousField and Config.gameFields[previousField] then - local lobbyPos = Config.gameFields[previousField].lobby.pos - SetEntityCoords(PlayerPedId(), lobbyPos.x, lobbyPos.y, lobbyPos.z) - elseif currentLobbyField and Config.gameFields[currentLobbyField] then - -- Zurück zur aktuellen Lobby - local lobbyPos = Config.gameFields[currentLobbyField].lobby.pos + -- 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 + else + for fieldId, fieldData in pairs(Config.gameFields) do + if fieldData.lobby and fieldData.lobby.pos then + lobbyPos = fieldData.lobby.pos + break + end + end + end + + -- Teleport zur Lobby (mit Fallback-Position) + if lobbyPos then SetEntityCoords(PlayerPedId(), lobbyPos.x, lobbyPos.y, lobbyPos.z) else - -- Fallback zur ersten Lobby - local firstField = next(Config.gameFields) - if firstField then - local lobbyPos = Config.gameFields[firstField].lobby.pos - SetEntityCoords(PlayerPedId(), lobbyPos.x, lobbyPos.y, lobbyPos.z) - end + -- 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 -- Maske entfernen @@ -95,7 +106,6 @@ RegisterNetEvent('tdm:leaveGame', function() }) end) --- Alle anderen Events bleiben gleich... RegisterNetEvent('tdm:joinRequest', function(gameId, playerName, playerId) local alert = lib.alertDialog({ header = 'Join Anfrage', @@ -219,7 +229,7 @@ RegisterNetEvent('tdm:gameEnded', function(winnerTeam, team1Score, team2Score) TriggerServerEvent('tdm:leaveGame') end) --- Angepasste setTeamMask Funktion +-- Funktionen function setTeamMask(team) local ped = PlayerPedId() local maskData = Config.teamMasks[team] @@ -236,64 +246,66 @@ function setTeamMask(team) end end --- Alternative Methode über QBCore Player Data -function setTeamMaskQB(team) - local ped = PlayerPedId() - local Player = QBCore.Functions.GetPlayerData() - local maskData = Config.teamMasks[team] +function createTeamZoneBlip(team, fieldConfig) + local zone = fieldConfig.teamZones[team] - if maskData and Player.charinfo then - -- Geschlecht aus QBCore Charinfo - local playerGender = Player.charinfo.gender == 1 and "female" or "male" - - -- Entsprechende Maske setzen - local genderMask = maskData[playerGender] - if genderMask then - SetPedComponentVariation(ped, genderMask.component, genderMask.drawable, genderMask.texture, 0) + 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 +end + +function removeTeamZoneBlips() + for team, blip in pairs(teamZoneBlips) do + if DoesBlipExist(blip) then + RemoveBlip(blip) end end + teamZoneBlips = {} +end + +function highlightTeamZone(team) + if teamZoneBlips[team] and DoesBlipExist(teamZoneBlips[team]) then + SetBlipFlashes(teamZoneBlips[team], true) + end end --- Erweiterte Funktion mit Fallback -function setTeamMaskAdvanced(team) - local ped = PlayerPedId() - local maskData = Config.teamMasks[team] - - if not maskData then return end - - local playerGender = "male" -- Default - - -- Methode 1: Über Ped Model - if GetEntityModel(ped) == GetHashKey("mp_f_freemode_01") then - playerGender = "female" - end - - -- Methode 2: Über QBCore (Fallback) - if playerGender == "male" then - local Player = QBCore.Functions.GetPlayerData() - if Player.charinfo and Player.charinfo.gender == 1 then - playerGender = "female" - end - end - - -- Maske setzen - local genderMask = maskData[playerGender] - if genderMask then - SetPedComponentVariation(ped, genderMask.component, genderMask.drawable, genderMask.texture, 0) +function showHitMarker() + CreateThread(function() + local startTime = GetGameTimer() - lib.notify({ - title = 'TeamDeathmatch', - description = 'Team-Maske (' .. playerGender .. ') angelegt!', - type = 'info', - duration = 2000 - }) - end + 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 - --- Angepasste Menü-Funktionen function openMainMenu(fieldId) - currentLobbyField = fieldId -- Aktuelle Lobby merken + -- Sicherheitscheck + if not fieldId or not Config.gameFields[fieldId] then + lib.notify({ + title = 'Fehler', + description = 'Ungültiges Spielfeld!', + type = 'error' + }) + return + end + + currentLobbyField = fieldId TriggerServerEvent('tdm:requestGamesList') Wait(100) @@ -341,6 +353,15 @@ function openMainMenu(fieldId) end function openCreateGameMenu(fieldId) + if not fieldId or not Config.gameFields[fieldId] then + lib.notify({ + title = 'Fehler', + description = 'Ungültiges Spielfeld!', + type = 'error' + }) + return + end + local fieldData = Config.gameFields[fieldId] local input = lib.inputDialog('Neues Spiel erstellen - ' .. fieldData.name, { @@ -381,6 +402,15 @@ function openCreateGameMenu(fieldId) end function openJoinGameMenu(fieldId) + if not fieldId or not Config.gameFields[fieldId] then + lib.notify({ + title = 'Fehler', + description = 'Ungültiges Spielfeld!', + type = 'error' + }) + return + end + TriggerServerEvent('tdm:requestGamesList') Wait(200) @@ -450,7 +480,7 @@ function openJoinGameMenu(fieldId) lib.showContext('tdm_join_menu_' .. fieldId) end --- Alle Threads bleiben gleich... +-- Zone Checker Thread CreateThread(function() while true do Wait(500) @@ -480,6 +510,7 @@ CreateThread(function() end end) +-- Zone Marker Renderer CreateThread(function() while true do Wait(0) @@ -515,6 +546,7 @@ CreateThread(function() end end) +-- Damage Handler CreateThread(function() while true do Wait(100) @@ -541,6 +573,7 @@ CreateThread(function() end end) +-- Death Handler CreateThread(function() while true do Wait(1000) @@ -564,58 +597,70 @@ CreateThread(function() end end) --- Angepasstes NPC Setup für alle Felder +-- NPC Setup für alle Felder CreateThread(function() -- Für jedes Spielfeld Blip und NPC erstellen for fieldId, fieldData in pairs(Config.gameFields) do - 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 + 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 + }, }, - }, - distance = 2.5 - }) + distance = 2.5 + }) + else + print("^3[TDM WARNING]^7 Feld " .. fieldId .. " hat keine vollständige Lobby-Konfiguration!") + end end end) -- Event für Feld-spezifisches Menü RegisterNetEvent('tdm:openFieldMenu', function(data) - openMainMenu(data.fieldId) + if data and data.fieldId then + openMainMenu(data.fieldId) + else + lib.notify({ + title = 'Fehler', + description = 'Keine Feld-ID übertragen!', + type = 'error' + }) + end end) -- Chat Command zum Spiel verlassen @@ -638,3 +683,62 @@ end, false) -- Keybind zum Spiel verlassen RegisterKeyMapping('leavetdm', 'TeamDeathmatch verlassen', 'keyboard', 'F7') + +-- 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)) + + 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)