1
0
Fork 0
forked from Simnation/Main
This commit is contained in:
Nordi98 2025-07-28 00:09:15 +02:00
parent 4485cc31df
commit 3afa513b4a
22 changed files with 1331 additions and 575 deletions

View file

@ -0,0 +1,28 @@
config.useDefaultInventory = true
local function log(msg)
print(string.format('\x1b[32m[tgiann-weapons-on-back]\x1b[0m %s', msg))
end
-- Chezza Studios inventory works fine with normal esx(don't add to the list)
local inventorys = {
"tgiann-inventory",
"mf-inventory",
"ox_inventory",
"core_inventory",
"qs-inventory",
"codem-inventory",
"origen_inventory"
}
for i = 1, #inventorys do
local inventory = inventorys[i]
local isStarted = GetResourceState(inventory) == "started"
if isStarted then
config[inventory] = true
config.useDefaultInventory = false
log(string.format("Started with %s inventory", inventory))
end
end
if config.useDefaultInventory then log(string.format("Started with %s default inventory", config.framework == "qb" and "QB" or "ESX")) end

View file

@ -0,0 +1,89 @@
if not config["codem-inventory"] then return end
local playerJob = ""
local lastItems = {}
RegisterNetEvent('tgiCore:Client:OnPlayerLogout', function()
self.Functions.RemoveAllWeapons()
end)
RegisterNetEvent('tgiCore:Client:OnPlayerLoaded')
AddEventHandler('tgiCore:Client:OnPlayerLoaded', function(PlayerData)
playerJob = PlayerData.job.name
SetTimeout(2000, function() -- some waiting time because the character's inventory data is loaded later
lastItems = exports['codem-inventory']:GetClientPlayerInventory()
weaponCheck()
end)
end)
RegisterNetEvent('tgiCore:Client:OnJobUpdate')
AddEventHandler('tgiCore:Client:OnJobUpdate', function(job)
self.Functions.RemoveAllWeapons()
playerJob = job.name
weaponCheck()
end)
RegisterNetEvent('codem-inventory:client:additem')
AddEventHandler('codem-inventory:client:additem', function(slot, data)
lastItems[tostring(slot)] = data
weaponCheck()
end)
RegisterNetEvent('codem-inventory:client:removeitemtoclientInventory')
AddEventHandler('codem-inventory:client:removeitemtoclientInventory', function(slot, amount)
slot = tostring(slot)
if lastItems[slot] then
local itemAmount = lastItems[slot].count or lastItems[slot].amount
if itemAmount == amount then
lastItems[slot] = nil
end
end
weaponCheck()
end)
RegisterNetEvent('codem-inventory:client:clearinventory')
AddEventHandler('codem-inventory:client:clearinventory', function()
lastItems = {}
weaponCheck()
end)
RegisterNetEvent('codem-inventory:client:setitembyslot')
AddEventHandler('codem-inventory:client:setitembyslot', function(slot, itemData)
lastItems[tostring(slot)] = itemData
weaponCheck()
end)
self.Functions.CheckWeaponIsRemoved = function()
if not next(self.weapons) then return end
for key, _ in pairs(self.weapons) do
local success = false
for _, item in pairs(lastItems) do
if key == item.info?.serie or item.name then
success = true
break
end
end
if not success then
self.Functions.RemoveWeapon(key)
end
end
end
function weaponCheck()
if not lastItems then return end
Wait(100)
self.Functions.CheckWeaponIsRemoved()
local isMale = GetEntityModel(PlayerPedId()) == `mp_m_freemode_01`
for _, item in pairs(lastItems) do
if item and item.type == "weapon" then
self.Functions.AddWeapon({
weapon = item.name,
key = item?.info?.serie or item.name,
attachments = config.tgiann_attachments and
getTgiannAttachments(item.info.tgiattachments, joaat(item.name)) or item.info.attachments,
playerJob = playerJob,
isMale = isMale
})
end
end
end

View file

@ -0,0 +1,116 @@
-- https://docs.c8re.store/core-inventory/api
if not config.core_inventory then return end
local function splitStr(str, delimiter)
local result = {}
local from = 1
local delim_from, delim_to = string.find(str, delimiter, from)
while delim_from do
result[#result + 1] = string.sub(str, from, delim_from - 1)
from = delim_to + 1
delim_from, delim_to = string.find(str, delimiter, from)
end
result[#result + 1] = string.sub(str, from)
return result
end
local playerJob = ""
local invItems = {}
local playerItems = {}
local function getInventoryItems()
tgiCore.cbFunction('tgiann-weapons-on-back:core_inventory:server:getInventory', function(newPlayerItems)
playerItems = newPlayerItems
weaponCheck(true)
end)
end
RegisterNetEvent('core_inventory:client:sync', function(inventory, data)
local split = splitStr(inventory, '-')[1]
if config.enableInv[split] then
playerItems[split] = data.content
end
end)
RegisterNetEvent('tgiCore:Client:OnPlayerLoaded')
AddEventHandler('tgiCore:Client:OnPlayerLoaded', function(PlayerData)
if not PlayerData then return end
playerJob = PlayerData.job.name
getInventoryItems(PlayerData.identifier)
end)
RegisterNetEvent('tgiCore:Client:OnPlayerLogout', function()
self.Functions.RemoveAllWeapons()
end)
RegisterNetEvent('tgiCore:Client:OnJobUpdate')
AddEventHandler('tgiCore:Client:OnJobUpdate', function(job)
self.Functions.RemoveAllWeapons()
playerJob = job.name
weaponCheck(false)
end)
if config.framework == "qb" then
RegisterNetEvent('QBCore:Player:SetPlayerData', function(PlayerData)
playerJob = PlayerData.job.name
if not config.enableInv["content"] then return end
playerItems["content"] = PlayerData?.items
weaponCheck(true)
end)
else
RegisterNetEvent('esx:addInventoryItem')
AddEventHandler('esx:addInventoryItem', function(job)
local PlayerData = exports["tgiann-core"]:getPlayerData()
if not PlayerData then return end
getInventoryItems(PlayerData.identifier)
end)
RegisterNetEvent('esx:removeInventoryItem')
AddEventHandler('esx:removeInventoryItem', function(job)
local PlayerData = exports["tgiann-core"]:getPlayerData()
if not PlayerData then return end
getInventoryItems(PlayerData.identifier)
end)
end
self.Functions.CheckWeaponIsRemoved = function()
if not next(self.weapons) then return end
for key, _ in pairs(self.weapons) do
local success = false
for _, item in pairs(invItems) do
if item and key == (item.metadata?.serial or item.name) then
success = true
break
end
end
if not success then
self.Functions.RemoveWeapon(key)
end
end
end
function weaponCheck(updateData)
if updateData then
invItems = {}
for _, inv in pairs(playerItems) do
for _, item in pairs(inv) do
invItems[#invItems + 1] = item
end
end
end
Wait(100)
self.Functions.CheckWeaponIsRemoved()
local isMale = GetEntityModel(PlayerPedId()) == `mp_m_freemode_01`
for _, item in pairs(invItems) do
if item and string.find(string.lower(item.name), "weapon") then
self.Functions.AddWeapon({
weapon = item.name,
key = item.metadata?.serial or item.name,
attachments = config.tgiann_attachments and
getTgiannAttachments(item.metadata.tgiattachments, joaat(item.name)) or item.metadata.attachments,
playerJob = playerJob,
isMale = isMale
})
end
end
end

View file

@ -0,0 +1,88 @@
if config.framework ~= "esx" then return end
if not config.useDefaultInventory then return end
local playerJob = ""
local lastItems = {}
local function getInventoryItems()
tgiCore.cbFunction('tgiann-weapons-on-back:esx_inv:server:getInventory', function(playerItems, loadout)
local itemList = {}
-- ESX is suck
if loadout and #loadout > 0 then
for i = 1, #loadout do
itemList[#itemList + 1] = loadout[i]
end
end
if playerItems and #playerItems > 0 then
for i = 1, #playerItems do
if playerItems[i].count > 0 then
itemList[#itemList + 1] = playerItems[i]
end
end
end
lastItems = itemList
weaponCheck()
end)
end
RegisterNetEvent('tgiCore:Client:OnPlayerLoaded')
AddEventHandler('tgiCore:Client:OnPlayerLoaded', function(PlayerData)
playerJob = PlayerData.job.name
getInventoryItems()
end)
RegisterNetEvent('tgiCore:Client:OnPlayerLogout', function()
self.Functions.RemoveAllWeapons()
end)
RegisterNetEvent('esx:addInventoryItem')
AddEventHandler('esx:addInventoryItem', function(job)
getInventoryItems()
end)
RegisterNetEvent('esx:removeInventoryItem')
AddEventHandler('esx:removeInventoryItem', function(job)
getInventoryItems()
end)
RegisterNetEvent('tgiCore:Client:OnJobUpdate')
AddEventHandler('tgiCore:Client:OnJobUpdate', function(job)
self.Functions.RemoveAllWeapons()
playerJob = job.name
weaponCheck()
end)
self.Functions.CheckWeaponIsRemoved = function()
if not next(self.weapons) then return end
for key, _ in pairs(self.weapons) do
local success = false
for _, item in pairs(lastItems) do
if item and key == item.name then
success = true
break
end
end
if not success then
self.Functions.RemoveWeapon(key)
end
end
end
function weaponCheck()
self.Functions.CheckWeaponIsRemoved()
Wait(100)
local isMale = GetEntityModel(PlayerPedId()) == `mp_m_freemode_01`
for _, item in pairs(lastItems) do
if item and string.find(string.lower(item.name), "weapon") then
self.Functions.AddWeapon({
weapon = item.name,
key = item.name,
attachments = config.tgiann_attachments and
getTgiannAttachments(item?.info?.tgiattachments, joaat(item.name)) or item.components,
playerJob = playerJob,
isMale = isMale
})
end
end
end

View file

@ -0,0 +1,99 @@
tgiCore = nil
CreateThread(function()
while not tgiCore do
tgiCore = tgiCoreExports:getCore()
Wait(200)
end
end)
local function LoadModel(model)
if HasModelLoaded(model) then return end
RequestModel(model)
while not HasModelLoaded(model) do Wait(0) end
end
self.Functions.AddAttachments = function(entity, weaponName, weaponHash, attachments)
if not attachments then return end
if config.tgiann_attachments then
for _, data in pairs(attachments) do
local model = GetWeaponComponentTypeModel(data.component)
if model ~= 0 then
LoadModel(model)
GiveWeaponComponentToWeaponObject(entity, data.component)
SetModelAsNoLongerNeeded(data.component)
else
SetWeaponObjectTintIndex(entity, data.component)
end
end
elseif config.core_inventory then
for _, data in pairs(attachments) do
local model = GetWeaponComponentTypeModel(data.componentHash)
if model ~= 0 then
LoadModel(model)
GiveWeaponComponentToWeaponObject(entity, data.componentHash)
SetModelAsNoLongerNeeded(data.componentHash)
else
SetWeaponObjectTintIndex(entity, data.componentHash)
end
end
elseif config.ox_inventory then
if not oxItems then oxItems = exports.ox_inventory:Items() end
for i = 1, #attachments do
local components = oxItems[attachments[i]].client.component
for v = 1, #components do
local component = components[v]
if DoesWeaponTakeWeaponComponent(weaponHash, component) then
local model = GetWeaponComponentTypeModel(component)
if model ~= 0 then
LoadModel(model)
GiveWeaponComponentToWeaponObject(entity, component)
SetModelAsNoLongerNeeded(component)
end
end
end
end
elseif config.framework == "qb" then
for _, data in pairs(attachments) do
local model = GetWeaponComponentTypeModel(data.component)
if model ~= 0 then
LoadModel(model)
GiveWeaponComponentToWeaponObject(entity, data.component)
SetModelAsNoLongerNeeded(data.component)
else
SetWeaponObjectTintIndex(entity, data.component)
end
end
else
--ESX is suck
for i = 1, #attachments do
local componentData = tgiCore.core.GetWeaponComponent(weaponName, attachments[i])
if componentData then
local hash = componentData.hash
local model = GetWeaponComponentTypeModel(hash)
if model ~= 0 then
LoadModel(model)
GiveWeaponComponentToWeaponObject(entity, hash)
SetModelAsNoLongerNeeded(hash)
else
SetWeaponObjectTintIndex(entity, hash)
end
end
end
end
end
function getTgiannAttachments(tgiattachments, weapon)
local invSettings = exports["tgiann-attachment"]:inventoryConfig()
if invSettings then
return tgiattachments
else
local returnVal = nil
local waitCb = true
tgiCore.cbFunction("tgiann-attachment:getAttachment", function(data)
returnVal = data
waitCb = false
end, weapon)
while waitCb do Wait(10) end
return returnVal
end
end

View file

@ -0,0 +1,77 @@
if not config["mf-inventory"] then return end
local playerJob = ""
local lastItems = {}
local function getInventoryItems(identifier)
exports["mf-inventory"]:getInventoryItems(identifier, function(items)
lastItems = items
weaponCheck()
end)
end
RegisterNetEvent('esx:playerLoaded')
AddEventHandler('esx:playerLoaded', function(PlayerData)
playerJob = PlayerData.job.name
getInventoryItems(PlayerData.identifier)
end)
RegisterNetEvent('tgiCore:Client:OnPlayerLogout', function()
self.Functions.RemoveAllWeapons()
end)
RegisterNetEvent('esx:addInventoryItem')
AddEventHandler('esx:addInventoryItem', function(job)
local PlayerData = exports["tgiann-core"]:getPlayerData()
if not PlayerData then return end
getInventoryItems(PlayerData.identifier)
end)
RegisterNetEvent('esx:removeInventoryItem')
AddEventHandler('esx:removeInventoryItem', function(job)
local PlayerData = exports["tgiann-core"]:getPlayerData()
if not PlayerData then return end
getInventoryItems(PlayerData.identifier)
end)
RegisterNetEvent('tgiCore:Client:OnJobUpdate')
AddEventHandler('tgiCore:Client:OnJobUpdate', function(job)
self.Functions.RemoveAllWeapons()
playerJob = job.name
weaponCheck()
end)
self.Functions.CheckWeaponIsRemoved = function()
if not next(self.weapons) then return end
for key, _ in pairs(self.weapons) do
local success = false
for _, item in pairs(lastItems) do
if item and key == item.name then
success = true
break
end
end
if not success then
self.Functions.RemoveWeapon(key)
end
end
end
function weaponCheck()
if not lastItems then return end
Wait(100)
self.Functions.CheckWeaponIsRemoved(lastItems)
local isMale = GetEntityModel(PlayerPedId()) == `mp_m_freemode_01`
for _, item in pairs(lastItems) do
if item and string.find(string.lower(item.name), "weapon") then
self.Functions.AddWeapon({
weapon = item.name,
key = item.name,
attachments = config.tgiann_attachments and
getTgiannAttachments(item.metadata.tgiattachments, joaat(item.name)),
playerJob = playerJob,
isMale = isMale
})
end
end
end

View file

@ -0,0 +1,79 @@
if not config.origen_inventory then return end
local origen_inventory = exports.origen_inventory
local playerJob = ""
local lastItems = {}
local function getInventoryItems()
lastItems = origen_inventory:GetInventory()
weaponCheck()
end
RegisterNetEvent('tgiCore:Client:OnPlayerLogout', function()
self.Functions.RemoveAllWeapons()
end)
RegisterNetEvent('tgiCore:Client:OnPlayerLoaded')
AddEventHandler('tgiCore:Client:OnPlayerLoaded', function(PlayerData)
playerJob = PlayerData.job.name
getInventoryItems()
end)
RegisterNetEvent('tgiCore:Client:OnJobUpdate')
AddEventHandler('tgiCore:Client:OnJobUpdate', function(job)
self.Functions.RemoveAllWeapons()
playerJob = job.name
weaponCheck()
end)
--QB
RegisterNetEvent('QBCore:Player:SetPlayerData', function(PlayerData)
playerJob = PlayerData.job.name
getInventoryItems()
end)
--ESX
RegisterNetEvent('esx:addInventoryItem')
AddEventHandler('esx:addInventoryItem', function()
getInventoryItems()
end)
RegisterNetEvent('esx:removeInventoryItem')
AddEventHandler('esx:removeInventoryItem', function()
getInventoryItems()
end)
self.Functions.CheckWeaponIsRemoved = function()
if not next(self.weapons) then return end
for key, _ in pairs(self.weapons) do
local success = false
for _, item in pairs(lastItems) do
if key == item.info.serie then
success = true
break
end
end
if not success then
self.Functions.RemoveWeapon(key)
end
end
end
function weaponCheck()
if not lastItems then return end
Wait(100)
self.Functions.CheckWeaponIsRemoved()
local isMale = GetEntityModel(PlayerPedId()) == `mp_m_freemode_01`
for _, item in pairs(lastItems) do
if item and item.type == "weapon" then
self.Functions.AddWeapon({
weapon = item.name,
key = item.info.serie,
attachments = config.tgiann_attachments and
getTgiannAttachments(item.info.tgiattachments, joaat(item.name)) or item.info.attachments,
playerJob = playerJob,
isMale = isMale
})
end
end
end

View file

@ -0,0 +1,64 @@
if not config.ox_inventory then return end
local playerJob = ""
local lastItems = {}
RegisterNetEvent('tgiCore:Client:OnPlayerLoaded')
AddEventHandler('tgiCore:Client:OnPlayerLoaded', function(PlayerData)
playerJob = PlayerData.job.name
lastItems = exports.ox_inventory:GetPlayerItems() or {}
weaponCheck()
end)
RegisterNetEvent('tgiCore:Client:OnPlayerLogout', function()
self.Functions.RemoveAllWeapons()
end)
AddEventHandler('ox_inventory:updateInventory', function(changes)
for i, value in pairs(changes) do
lastItems[i] = value or nil
end
weaponCheck()
end)
RegisterNetEvent('tgiCore:Client:OnJobUpdate')
AddEventHandler('tgiCore:Client:OnJobUpdate', function(job)
self.Functions.RemoveAllWeapons()
playerJob = job.name
weaponCheck()
end)
self.Functions.CheckWeaponIsRemoved = function()
if not next(self.weapons) then return end
for key, _ in pairs(self.weapons) do
local success = false
for _, item in pairs(lastItems) do
if item and key == (item.metadata.serial or item.name) then
success = true
break
end
end
if not success then
self.Functions.RemoveWeapon(key)
end
end
end
function weaponCheck()
if not lastItems then return end
Wait(100)
self.Functions.CheckWeaponIsRemoved()
local isMale = GetEntityModel(PlayerPedId()) == `mp_m_freemode_01`
for _, item in pairs(lastItems) do
if item and string.find(string.lower(item.name), "weapon") then
self.Functions.AddWeapon({
weapon = item.name,
key = item.metadata.serial or item.name,
attachments = config.tgiann_attachments and
getTgiannAttachments(item.metadata.tgiattachments, joaat(item.name)) or item.metadata.components,
playerJob = playerJob,
isMale = isMale
})
end
end
end

View file

@ -0,0 +1,64 @@
if config.framework ~= "qb" then return end
if not config.useDefaultInventory then return end
local playerJob = ""
local lastItems = {}
RegisterNetEvent('tgiCore:Client:OnPlayerLogout', function()
self.Functions.RemoveAllWeapons()
end)
RegisterNetEvent('tgiCore:Client:OnPlayerLoaded')
AddEventHandler('tgiCore:Client:OnPlayerLoaded', function(PlayerData)
playerJob = PlayerData.job.name
lastItems = PlayerData?.items
weaponCheck()
end)
RegisterNetEvent('QBCore:Player:SetPlayerData', function(PlayerData)
playerJob = PlayerData.job.name
lastItems = PlayerData?.items
weaponCheck()
end)
RegisterNetEvent('tgiCore:Client:OnJobUpdate')
AddEventHandler('tgiCore:Client:OnJobUpdate', function(job)
self.Functions.RemoveAllWeapons()
playerJob = job.name
weaponCheck()
end)
self.Functions.CheckWeaponIsRemoved = function()
if not next(self.weapons) then return end
for key, _ in pairs(self.weapons) do
local success = false
for _, item in pairs(lastItems) do
if key == item.info.serie then
success = true
break
end
end
if not success then
self.Functions.RemoveWeapon(key)
end
end
end
function weaponCheck()
if not lastItems then return end
Wait(100)
self.Functions.CheckWeaponIsRemoved()
local isMale = GetEntityModel(PlayerPedId()) == `mp_m_freemode_01`
for _, item in pairs(lastItems) do
if item and item.type == "weapon" then
self.Functions.AddWeapon({
weapon = item.name,
key = item.info.serie,
attachments = config.tgiann_attachments and
getTgiannAttachments(item.info.tgiattachments, joaat(item.name)) or item.info.attachments,
playerJob = playerJob,
isMale = isMale
})
end
end
end

View file

@ -0,0 +1,89 @@
if not config["qs-inventory"] then return end
local playerJob = ""
local lastItems = {}
local isBussy = false
local function getInventoryItems()
if isBussy then return end
isBussy = true
while exports['qs-inventory']:inInventory() do Wait(10) end -- getUserInventory not updating when inventory is open
Wait(1000) -- getUserInventory is updating late
lastItems = exports['qs-inventory']:getUserInventory()
weaponCheck(playerJob, true)
isBussy = false
end
RegisterNetEvent('tgiCore:Client:OnPlayerLoaded')
AddEventHandler('tgiCore:Client:OnPlayerLoaded', function(PlayerData)
playerJob = PlayerData.job.name
getInventoryItems()
end)
RegisterNetEvent('tgiCore:Client:OnPlayerLogout', function()
self.Functions.RemoveAllWeapons()
end)
--ESX
RegisterNetEvent('esx:addInventoryItem')
AddEventHandler('esx:addInventoryItem', function()
getInventoryItems()
end)
RegisterNetEvent('esx:removeInventoryItem')
AddEventHandler('esx:removeInventoryItem', function()
getInventoryItems()
end)
--QB
RegisterNetEvent('QBCore:Player:SetPlayerData', function(PlayerData)
playerJob = PlayerData.job.name
lastItems = PlayerData?.items
weaponCheck()
end)
RegisterNetEvent('tgiCore:Client:OnJobUpdate')
AddEventHandler('tgiCore:Client:OnJobUpdate', function(job)
self.Functions.RemoveAllWeapons()
playerJob = job.name
weaponCheck(playerJob)
end)
self.Functions.CheckWeaponIsRemoved = function()
if not next(self.weapons) then return end
for key, _ in pairs(self.weapons) do
local success = false
for _, item in pairs(lastItems) do
if item and key == (item.info?.serie or item.name) then
success = true
break
end
end
if not success then
self.Functions.RemoveWeapon(key)
end
end
end
function weaponCheck()
Wait(100)
self.Functions.CheckWeaponIsRemoved()
local isMale = GetEntityModel(PlayerPedId()) == `mp_m_freemode_01`
for _, item in pairs(lastItems) do
if item then
local isWeapon = string.find(string.lower(item.name), "weapon")
debug(item.name .. " Check For Add Weapon", "isWeapon: " .. tostring(isWeapon))
if isWeapon then
debug(item.name .. " Added")
self.Functions.AddWeapon({
weapon = item.name,
key = item.info?.serie or item.name,
attachments = config.tgiann_attachments and
getTgiannAttachments(item.info.tgiattachments, joaat(item.name)) or item.info?.attachments,
playerJob = playerJob,
isMale = isMale
})
end
end
end
end

View file

@ -0,0 +1,62 @@
if not config["tgiann-inventory"] then return end
local playerJob = ""
local lastItems = {}
RegisterNetEvent('tgiCore:Client:OnPlayerLogout', function()
self.Functions.RemoveAllWeapons()
end)
RegisterNetEvent('tgiCore:Client:OnPlayerLoaded')
AddEventHandler('tgiCore:Client:OnPlayerLoaded', function(PlayerData)
playerJob = PlayerData.job.name
lastItems = exports["tgiann-inventory"]:GetPlayerItems()
weaponCheck()
end)
RegisterNetEvent('tgiann-inventory:inventoryUpdated')
AddEventHandler('tgiann-inventory:inventoryUpdated', function(items)
lastItems = items
weaponCheck()
end)
RegisterNetEvent('tgiCore:Client:OnJobUpdate')
AddEventHandler('tgiCore:Client:OnJobUpdate', function(job)
self.Functions.RemoveAllWeapons()
playerJob = job.name
weaponCheck()
end)
self.Functions.CheckWeaponIsRemoved = function()
if not next(self.weapons) then return end
for key, _ in pairs(self.weapons) do
local success = false
for _, item in pairs(lastItems) do
if key == item?.info?.serie then
success = true
break
end
end
if not success then
self.Functions.RemoveWeapon(key)
end
end
end
function weaponCheck()
if not lastItems then return end
Wait(100)
self.Functions.CheckWeaponIsRemoved()
local isMale = GetEntityModel(PlayerPedId()) == `mp_m_freemode_01`
for _, item in pairs(lastItems) do
if item and item.type == "weapon" then
self.Functions.AddWeapon({
weapon = string.gsub(item.name, "_police", ""),
key = item?.info?.serie or item.name,
attachments = item?.info?.tgiattachments or {},
playerJob = playerJob,
isMale = isMale
})
end
end
end

View file

@ -0,0 +1,12 @@
function canShow(targetPed)
local isEntityVisible = IsEntityVisible(targetPed)
local getEntityAlpha = GetEntityAlpha(targetPed)
local pedIsVisible = isEntityVisible and getEntityAlpha == 255
debug("pedIsVisible: " .. tostring(pedIsVisible), "ped:" .. targetPed, "isEntityVisible: " .. tostring(isEntityVisible), "getEntityAlpha: " .. getEntityAlpha)
return pedIsVisible
end
function debug(...)
if not config.debug then return end
print(...)
end

View file

@ -0,0 +1,206 @@
--[[
- this script needs tgiann-core script to work, you can download the script from your keymaster account
Start tgiann-core script after es_extented/qb-core script and before tgiann-* scripts
Adjust the tgiann-core config file according to the framework you are using
https://tgiann.gitbook.io/tgiann/scripts/tgiann-weapons-on-back
Note: If you want the weapons to be invisible while in Noclip, the character must be completely invisible. If your character is invisible to other players, other players cannot see these weapons.
If you want to edit this, take a look at client/editable.lua
]]
tgiCoreExports = exports["tgiann-core"]
config = tgiCoreExports:getConfig()
config.debug = false
config.tgiann_attachments = GetResourceState("tgiann-attachment") ~= "missing" -- https://tgiann.tebex.io/package/5399235
-- Weapon positions for male and female characters. You can add additional positions here if you like.
config.positions = {
male = {
back = { -- We have set 3 positions for the back. You can add or remove extra positions if you like. This setting also applies to other positions.
{ -- position 1
bone = 24816,
offset = vector3(0.285, -0.17, 0.13),
rot = vector3(0.0, 170.0, 0.0),
},
{ -- position 2
bone = 24816,
offset = vector3(0.285, -0.17, 0.0),
rot = vector3(0.0, 170.0, 0.0),
},
{ -- position 3
bone = 24816,
offset = vector3(0.285, -0.17, -0.13),
rot = vector3(0.0, 170.0, 0.0),
}
},
front = {
{
bone = 24818,
offset = vector3(-0.03, 0.19, 0.0),
rot = vector3(-10.0, 40.0, 5.0),
}
},
right = {
{
bone = 11816,
offset = vector3(-0.01, 0.02, 0.215),
rot = vector3(-100.0, 60.0, 45.0),
}
},
rLegBack = {
{
bone = 11816,
offset = vector3(-0.15, -0.11, 0.22),
rot = vector3(0.0, 95.0, 180.0),
}
},
waist = {
{
bone = 11816,
offset = vector3(-0.07, -0.13, 0.05),
rot = vector3(180.0, -30.0, 10.0),
}
},
-- You can add extra positions here if you like.
-- The positions you add can be used in the `config.weaponPositions`, `config.weaponGroupPositions` and `config.weaponGroupJobPositions` settings.
--[[ exampleCustomName = {
{
bone = 11816,
offset = vector3(-0.07, -0.13, 0.05),
rot = vector3(180.0, -30.0, 10.0),
}
}, ]]
},
female = {
back = {
{
bone = 24816,
offset = vector3(0.285, -0.15, 0.13),
rot = vector3(0.0, 170.0, 0.0),
},
{
bone = 24816,
offset = vector3(0.285, -0.15, 0.0),
rot = vector3(0.0, 170.0, 0.0),
},
{
bone = 24816,
offset = vector3(0.285, -0.15, -0.13),
rot = vector3(0.0, 170.0, 0.0),
}
},
front = {
{
bone = 24818,
offset = vector3(-0.03, 0.21, 0.0),
rot = vector3(-10.0, 40.0, 5.0),
}
},
right = {
{
bone = 11816,
offset = vector3(-0.09, 0.03, 0.18),
rot = vector3(-105.0, 75.0, 45.0),
}
},
rLegBack = {
{
bone = 11816,
offset = vector3(-0.15, -0.11, 0.22),
rot = vector3(0.0, 95.0, 180.0),
}
},
waist = {
{
bone = 11816,
offset = vector3(-0.07, -0.09, 0.05),
rot = vector3(180.0, -30.0, 10.0),
}
}
}
}
-- Weapons in the list do not appear on the character
config.disabledWeapons = {
weapon_flashlight = true,
weapon_knuckle = true,
weapon_bottle = true,
weapon_snowball = true,
}
-- adjusts the location of the weapon regardless of its group
config.weaponPositions = {
--weapon_pistol = "right",
}
-- adjusts the position of the weapon regardless of its group
config.weaponCustomPositions = {
male = {
weapon_bat = {
bone = 24816,
offset = vector3(0.0, -0.15, 0.03),
rot = vector3(0.0, 80.0, 0.0),
}
},
female = {
weapon_bat = {
bone = 24816,
offset = vector3(0.0, -0.15, 0.03),
rot = vector3(0.0, 80.0, 0.0),
}
}
}
--"waist" - "back" - "front" - "rigt" - "rLegBack" - "none"
config.weaponGroupPostions = {
[3539449195] = "back", --GROUP_DIGISCANNER
[-37788308] = "rLegBack", --GROUP_FIREEXTINGUISHER
[1175761940] = "none", --GROUP_HACKINGDEVICE
[2725924767] = "back", --GROUP_HEAVY
[-728555052] = "back", --GROUP_MELEE
[3759491383] = "none", --GROUP_METALDETECTOR
[1159398588] = "back", --GROUP_MG
[3493187224] = "none", --GROUP_NIGHTVISION
[431593103] = "none", --GROUP_PARACHUTE
[1595662460] = "none", --GROUP_PETROLCAN
[416676503] = "waist", --GROUP_PISTOL
[970310034] = "back", --GROUP_RIFLE
[860033945] = "back", --GROUP_SHOTGUN
[-957766203] = "front", --GROUP_SMG
[-1212426201] = "back", --GROUP_SNIPER
[690389602] = "none", --GROUP_STUNGUN
[1548507267] = "none", --GROUP_THROWN
[75159441] = "back", --GROUP_TRANQILIZER
[2685387236] = "none", --GROUP_UNARMED
}
-- weapon locations for jobs
config.weaponGroupJobPostions = {
{
jobs = { "police" }, -- u can add multible job name
postions = {
[3539449195] = "back", --GROUP_DIGISCANNER
[-37788308] = "rLegBack", --GROUP_FIREEXTINGUISHER
[1175761940] = "none", --GROUP_HACKINGDEVICE
[2725924767] = "back", --GROUP_HEAVY
[-728555052] = "back", --GROUP_MELEE
[3759491383] = "none", --GROUP_METALDETECTOR
[1159398588] = "back", --GROUP_MG
[3493187224] = "none", --GROUP_NIGHTVISION
[431593103] = "none", --GROUP_PARACHUTE
[1595662460] = "none", --GROUP_PETROLCAN
[416676503] = "right", --GROUP_PISTOL
[970310034] = "back", --GROUP_RIFLE
[860033945] = "back", --GROUP_SHOTGUN
[-957766203] = "front", --GROUP_SMG
[-1212426201] = "back", --GROUP_SNIPER
[690389602] = "none", --GROUP_STUNGUN
[1548507267] = "none", --GROUP_THROWN
[75159441] = "back", --GROUP_TRANQILIZER
[2685387236] = "none", --GROUP_UNARMED
}
}
}

View file

@ -0,0 +1,5 @@
config.enableInv = {
["content"] = true,
["primary"] = true,
["secondry"] = true,
}

View file

@ -0,0 +1,34 @@
fx_version 'cerulean'
game 'gta5'
version '1.0.1'
lua54 'yes'
dependencies {
'tgiann-core',
}
escrow_ignore {
'configs/*.lua',
'checkInv.lua',
'client/bridge/*.lua',
'client/editable.lua',
'server/bridge/*.lua'
}
shared_script {
'configs/*.lua',
'checkInv.lua',
}
client_scripts {
'client/*.lua',
'client/bridge/*.lua'
}
server_scripts {
"server/server.lua",
'server/bridge/*.lua',
}
dependency '/assetpacks'

View file

@ -0,0 +1,13 @@
if not config.core_inventory then return end
tgiCore.cbFunction('tgiann-weapons-on-back:core_inventory:server:getInventory', function(source, cb)
local src = source
local xPlayer = tgiCore.getPlayer(src)
if not xPlayer then return end
local citizenid = tgiCore.getCid(xPlayer)
local playerItems = {}
for inv, canAdd in pairs(config.enableInv) do
if canAdd then playerItems[inv] = exports['core_inventory']:getInventory(string.format("%s-%s", inv, citizenid)) end
end
cb(playerItems)
end)

View file

@ -0,0 +1,10 @@
if config.framework ~= "esx" then return end
if not config.useDefaultInventory then return end
-- esx is very bad, I can't access current inventory data from client
tgiCore.cbFunction('tgiann-weapons-on-back:esx_inv:server:getInventory', function(source, cb)
local src = source
local xPlayer = tgiCore.getPlayer(src)
if not xPlayer then return end
cb(xPlayer.getInventory(), xPlayer.getLoadout())
end)

View file

@ -25,19 +25,6 @@ local function debugPrint(message)
print("^2[TDM DEBUG]^7 " .. message)
end
-- Funktion zum Prüfen, ob eine Waffe eine Airsoft-Waffe ist
function isAirsoftWeapon(weaponHash)
return Config.airsoftWeapons[weaponHash] or Config.treatAllWeaponsAsAirsoft
end
-- Enhanced function to check if a player is in ragdoll state
function isPedInRagdoll(ped)
return IsPedRagdoll(ped) or
IsPedFalling(ped) or
IsPedDiving(ped) or
(not IsPedStill(ped) and IsPedOnFoot(ped) and not IsPedWalking(ped) and not IsPedRunning(ped) and not IsPedSprinting(ped))
end
-- Helper function to dump tables for debugging
function dumpTable(table, indent)
if not indent then indent = 0 end
@ -52,6 +39,19 @@ function dumpTable(table, indent)
end
end
-- Funktion zum Prüfen, ob eine Waffe eine Airsoft-Waffe ist
function isAirsoftWeapon(weaponHash)
return Config.airsoftWeapons[weaponHash] or Config.treatAllWeaponsAsAirsoft
end
-- Enhanced function to check if a player is in ragdoll state
function isPedInRagdoll(ped)
return IsPedRagdoll(ped) or
IsPedFalling(ped) or
IsPedDiving(ped) or
(not IsPedStill(ped) and IsPedOnFoot(ped) and not IsPedWalking(ped) and not IsPedRunning(ped) and not IsPedSprinting(ped))
end
-- Events
RegisterNetEvent('tdm:updateGamesList', function(games)
activeGames = games
@ -791,566 +791,184 @@ CreateThread(function()
if inTDM and not isHit then
local ped = PlayerPedId()
-- Prüfe, ob der Spieler im Ragdoll-Zustand ist
if
-- Prüfe, ob der Spieler im Ragdoll-Zustand ist
if isPedInRagdoll(ped) then
-- Bestimme den Angreifer (verwende den letzten Angreifer, wenn innerhalb von 3 Sekunden)
local attacker = nil
if lastDamager and (GetGameTimer() -
local QBCore = exports['qb-core']:GetCoreObject()
if lastDamager and (GetGameTimer() - lastDamageTime) < 3000 then
attacker = lastDamager
-- Game Management
local activeGames = {}
local gameIdCounter = 1
-- Prüfe ob die Waffe eine Airsoft-Waffe ist
if isAirsoftWeapon(lastDamageWeapon) then
debugPrint("Ragdoll durch Airsoft-Waffe - Zählt als Tod durch: " .. attacker)
-- Debug-Funktion für Konsole
local function debugPrint(message)
print("^2[TDM SERVER]^7 " .. message)
end
-- Lokale Stats sofort updaten
playerStats.deaths = playerStats.deaths + 1
-- Events
RegisterNetEvent('tdm:createGame', function(gameName, fieldId, gameType, password)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
-- Treffer-Events auslösen
TriggerEvent('tdm:playerHit')
TriggerServerEvent('tdm:playerWasHit', currentGameId, currentTeam, attacker)
if not Player then
debugPrint("Spielerstellung fehlgeschlagen - Spieler nicht gefunden: " .. src)
return
end
-- Zurücksetzen des letzten Angreifers
lastDamager = nil
lastDamageWeapon = 0
-- Prüfen ob Spielfeld bereits belegt
for gameId, gameData in pairs(activeGames) do
if gameData.fieldId == fieldId then
debugPrint("Spielerstellung abgelehnt - Feld bereits belegt: " .. fieldId)
TriggerClientEvent('QBCore:Notify', src, 'Dieses Spielfeld ist bereits belegt!', 'error')
return
end
end
local gameId = 'game_' .. gameIdCounter
gameIdCounter = gameIdCounter + 1
activeGames[gameId] = {
id = gameId,
name = gameName,
fieldId = fieldId,
admin = src,
adminName = Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname,
gameType = gameType,
password = password,
hasPassword = password ~= nil,
status = 'waiting',
team1 = {},
team2 = {},
score = {team1 = 0, team2 = 0},
startTime = nil,
maxTime = Config.maxGameTime,
maxHits = Config.maxHits,
playerStats = {} -- Spieler-Statistiken initialisieren
}
local typeText = gameType == 'public' and 'öffentliches' or 'privates'
TriggerClientEvent('QBCore:Notify', src, 'Dein ' .. typeText .. ' Spiel "' .. gameName .. '" wurde erstellt!', 'success')
updateGamesListForAll()
debugPrint("Spiel erstellt: " .. gameId .. " von " .. Player.PlayerData.name .. " (Feld: " .. fieldId .. ")")
end)
RegisterNetEvent('tdm:requestGamesList', function()
local src = source
debugPrint("Spiele-Liste angefordert von: " .. src)
TriggerClientEvent('tdm:updateGamesList', src, activeGames)
end)
RegisterNetEvent('tdm:requestJoinGame', function(gameId, password)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player or not activeGames[gameId] then
debugPrint("Spielbeitritt fehlgeschlagen - Spieler oder Spiel nicht gefunden: " .. src .. ", " .. gameId)
return
end
local game = activeGames[gameId]
local playerName = Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname
debugPrint("Beitrittsanfrage von " .. playerName .. " (ID: " .. src .. ") für Spiel " .. gameId)
-- Passwort prüfen falls vorhanden
if game.hasPassword and game.password ~= password then
debugPrint("Beitritt abgelehnt - Falsches Passwort")
TriggerClientEvent('QBCore:Notify', src, 'Falsches Passwort!', 'error')
return
end
-- Spieler bereits im Spiel?
for _, playerId in ipairs(game.team1) do
if playerId == src then
debugPrint("Beitritt abgelehnt - Spieler bereits in Team 1")
TriggerClientEvent('QBCore:Notify', src, 'Du bist bereits in diesem Spiel!', 'error')
return
end
end
for _, playerId in ipairs(game.team2) do
if playerId == src then
debugPrint("Beitritt abgelehnt - Spieler bereits in Team 2")
TriggerClientEvent('QBCore:Notify', src, 'Du bist bereits in diesem Spiel!', 'error')
return
end
end
-- Max Spieler erreicht?
local currentPlayers = #game.team1 + #game.team2
local maxPlayers = Config.gameFields[game.fieldId].maxPlayers
if currentPlayers >= maxPlayers then
debugPrint("Beitritt abgelehnt - Spiel ist voll")
TriggerClientEvent('QBCore:Notify', src, 'Spiel ist voll!', 'error')
return
end
-- Prüfen ob Admin online ist (für private Spiele)
if game.gameType == 'private' then
local AdminPlayer = QBCore.Functions.GetPlayer(game.admin)
if not AdminPlayer then
debugPrint("Beitritt abgelehnt - Admin nicht online")
TriggerClientEvent('QBCore:Notify', src, 'Der Spiel-Admin ist nicht online!', 'error')
return
end
end
-- Join Logic basierend auf Spiel Typ
if game.gameType == 'public' then
debugPrint("Öffentliches Spiel - Direkter Beitritt")
joinPlayerToGame(src, gameId)
TriggerClientEvent('QBCore:Notify', src, 'Du bist dem öffentlichen Spiel beigetreten!', 'success')
else
debugPrint("Privates Spiel - Sende Anfrage an Admin")
TriggerClientEvent('tdm:joinRequest', game.admin, gameId, playerName, src)
TriggerClientEvent('QBCore:Notify', src, 'Join-Anfrage gesendet an ' .. game.adminName, 'info')
end
end)
RegisterNetEvent('tdm:approveJoinRequest', function(gameId, playerId, approved)
local src = source
local game = activeGames[gameId]
if not game or game.admin ~= src then
debugPrint("Join-Anfrage Bearbeitung fehlgeschlagen - Ungültiges Spiel oder nicht Admin")
return
end
if approved then
debugPrint("Join-Anfrage genehmigt für Spieler " .. playerId .. " in Spiel " .. gameId)
joinPlayerToGame(playerId, gameId)
TriggerClientEvent('tdm:joinRequestResult', playerId, true, game.name)
else
debugPrint("Join-Anfrage abgelehnt für Spieler " .. playerId .. " in Spiel " .. gameId)
TriggerClientEvent('tdm:joinRequestResult', playerId, false, game.name)
end
end)
RegisterNetEvent('tdm:leaveGame', function()
local src = source
debugPrint("Spieler " .. src .. " möchte alle Spiele verlassen")
for gameId, game in pairs(activeGames) do
removePlayerFromGame(src, gameId)
end
TriggerClientEvent('tdm:leaveGame', src)
end)
RegisterNetEvent('tdm:playerWasHit', function(gameId, victimTeam, attackerId)
local victim = source
if not activeGames[gameId] then
debugPrint("Hit registriert, aber Spiel " .. gameId .. " existiert nicht!")
return
end
local game = activeGames[gameId]
debugPrint("Hit registriert - Opfer: " .. victim .. " (Team: " .. victimTeam .. "), Angreifer: " .. (attackerId or "Unbekannt"))
-- Spieler Stats initialisieren falls nicht vorhanden
if not game.playerStats then
game.playerStats = {}
end
if not game.playerStats[victim] then
game.playerStats[victim] = {hits = 0, deaths = 0}
end
-- Wichtig: Nur wenn ein Angreifer identifiziert wurde, zähle den Kill
if attackerId then
if not game.playerStats[attackerId] then
game.playerStats[attackerId] = {hits = 0, deaths = 0}
end
-- Stats updaten
game.playerStats[victim].deaths = (game.playerStats[victim].deaths or 0) + 1
game.playerStats[attackerId].hits = (game.playerStats[attackerId].hits or 0) + 1
-- Benachrichtigung an den Angreifer senden
TriggerClientEvent('tdm:hitRegistered', attackerId)
debugPrint("Treffer von " .. attackerId .. " gegen " .. victim .. " registriert")
-- Team Score erhöhen
if victimTeam == 'team1' then
game.score.team2 = game.score.team2 + 1
debugPrint("Punkt für Team 2 - Neuer Score: " .. game.score.team2)
else
game.score.team1 = game.score.team1 + 1
debugPrint("Punkt für Team 1 - Neuer Score: " .. game.score.team1)
end
else
debugPrint("Treffer gegen " .. victim .. " von unbekanntem Angreifer registriert - Kein Punkt vergeben")
end
TriggerClientEvent('tdm:deathRegistered', victim)
-- Score an alle Spieler senden
updateScoreForGame(gameId)
-- Spiel beenden prüfen
if game.score.team1 >= game.maxHits or game.score.team2 >= game.maxHits then
local winnerTeam = game.score.team1 >= game.maxHits and 'team1' or 'team2'
debugPrint("Max Punkte erreicht - Beende Spiel. Gewinner: " .. winnerTeam)
endGame(gameId, winnerTeam)
end
end)
RegisterNetEvent('tdm:playerDied', function(gameId)
local src = source
debugPrint("Spieler " .. src .. " ist gestorben in Spiel " .. gameId)
removePlayerFromGame(src, gameId)
end)
RegisterNetEvent('tdm:requestScoreUpdate', function(gameId)
local src = source
if activeGames[gameId] then
debugPrint("Score-Update angefordert von " .. src .. " für Spiel " .. gameId)
updateScoreForGame(gameId)
else
debugPrint("Score-Update fehlgeschlagen - Spiel " .. gameId .. " nicht gefunden")
end
end)
RegisterNetEvent('tdm:debugPlayerStats', function(gameId)
local src = source
if activeGames[gameId] and activeGames[gameId].playerStats and activeGames[gameId].playerStats[src] then
local stats = activeGames[gameId].playerStats[src]
debugPrint("Stats für Spieler " .. src .. ": Hits=" .. (stats.hits or 0) .. ", Deaths=" .. (stats.deaths or 0))
TriggerClientEvent('QBCore:Notify', src, 'Server Stats - Hits: ' .. (stats.hits or 0) .. ', Deaths: ' .. (stats.deaths or 0), 'info')
else
debugPrint("Keine Stats gefunden für Spieler " .. src .. " in Spiel " .. gameId)
TriggerClientEvent('QBCore:Notify', src, 'Keine Stats gefunden!', 'error')
end
end)
-- Funktionen
function joinPlayerToGame(playerId, gameId)
local game = activeGames[gameId]
if not game then
debugPrint("Spielbeitritt fehlgeschlagen - Spiel nicht gefunden: " .. gameId)
return
end
-- Team mit weniger Spielern wählen
local team = #game.team1 <= #game.team2 and 'team1' or 'team2'
table.insert(game[team], playerId)
-- Spieler-Stats initialisieren
if not game.playerStats then
game.playerStats = {}
end
game.playerStats[playerId] = {hits = 0, deaths = 0}
-- Spiel starten wenn mindestens 2 Spieler
if #game.team1 + #game.team2 >= 2 and game.status == 'waiting' then
game.status = 'active'
game.startTime = os.time()
debugPrint("Spiel " .. gameId .. " gestartet - Mindestens 2 Spieler erreicht")
-- Game Timer starten
startGameTimer(gameId)
end
TriggerClientEvent('tdm:joinGame', playerId, gameId, team, game.fieldId)
updateScoreForGame(gameId)
updateGamesListForAll()
debugPrint("Spieler " .. playerId .. " ist Spiel " .. gameId .. " beigetreten (Team: " .. team .. ")")
end
function removePlayerFromGame(playerId, gameId)
local game = activeGames[gameId]
if not game then return end
-- Spieler aus Teams entfernen
local removed = false
for i, id in ipairs(game.team1) do
if id == playerId then
table.remove(game.team1, i)
debugPrint("Spieler " .. playerId .. " aus Team 1 entfernt")
removed = true
break
end
end
if not removed then
for i, id in ipairs(game.team2) do
if id == playerId then
table.remove(game.team2, i)
debugPrint("Spieler " .. playerId .. " aus Team 2 entfernt")
removed = true
break
end
end
end
if not removed then
debugPrint("Spieler " .. playerId .. " nicht in Spiel " .. gameId .. " gefunden")
return
end
-- Wenn Admin das Spiel verlässt, Spiel beenden
if game.admin == playerId then
debugPrint("Admin hat das Spiel verlassen - Beende Spiel " .. gameId)
endGame(gameId, nil, 'Admin hat das Spiel verlassen')
return
end
checkGameEnd(gameId)
updateGamesListForAll()
end
function endGame(gameId, winnerTeam, reason)
local game = activeGames[gameId]
if not game then
debugPrint("Spielende fehlgeschlagen - Spiel nicht gefunden: " .. gameId)
return
end
game.status = 'finished'
local allPlayers = {}
for _, playerId in ipairs(game.team1) do
table.insert(allPlayers, playerId)
end
for _, playerId in ipairs(game.team2) do
table.insert(allPlayers, playerId)
end
-- Game End Event an alle Spieler
for _, playerId in ipairs(allPlayers) do
debugPrint("Sende Spielende-Event an Spieler " .. playerId)
TriggerClientEvent('tdm:gameEnded', playerId, winnerTeam, game.score.team1, game.score.team2)
end
-- Spiel nach 10 Sekunden löschen
SetTimeout(10000, function()
activeGames[gameId] = nil
updateGamesListForAll()
debugPrint("Spiel " .. gameId .. " aus der Liste entfernt")
end)
if reason then
debugPrint("Spiel " .. gameId .. " beendet: " .. reason)
else
debugPrint("Spiel " .. gameId .. " beendet. Gewinner: " .. (winnerTeam or "Unentschieden"))
end
end
function startGameTimer(gameId)
CreateThread(function()
local game = activeGames[gameId]
if not game then return end
local maxTime = game.maxTime
local startTime = os.time()
debugPrint("Timer für Spiel " .. gameId .. " gestartet. Maximale Zeit: " .. maxTime .. " Sekunden")
while game and game.status == 'active' and (os.time() - startTime) < maxTime do
-- Warten um mehrfache Auslösung zu verhindern
Wait(1000)
game = activeGames[gameId] -- Refresh game data
-- Alle 30 Sekunden Debug-Info
if (os.time() - startTime) % 30 == 0 then
debugPrint("Spiel " .. gameId .. " läuft seit " .. (os.time() - startTime) .. " Sekunden")
end
end
-- Zeit abgelaufen
if game and game.status == 'active' then
local winnerTeam = game.score.team1 > game.score.team2 and 'team1' or
game.score.team2 > game.score.team1 and 'team2' or nil
debugPrint("Spielzeit abgelaufen - Beende Spiel " .. gameId)
endGame(gameId, winnerTeam, 'Zeit abgelaufen')
end
else
Wait(500)
end
end
end)
-- Direkter Waffen-Schaden Monitor für zusätzliche Zuverlässigkeit
CreateThread(function()
while true do
Wait(0)
if inTDM and not isHit then
local ped = PlayerPedId()
-- Prüfe auf Projektil-Treffer
if HasEntityBeenDamagedByWeapon(ped, 0, 2) then -- 2 = Projektilwaffen
debugPrint("Projektil-Treffer erkannt")
-- Schaden zurücksetzen
ClearEntityLastDamageEntity(ped)
ClearPedLastWeaponDamage(ped)
SetEntityHealth(ped, GetEntityMaxHealth(ped))
-- Lokale Stats sofort updaten
playerStats.deaths = playerStats.deaths + 1
-- Treffer-Events auslösen
TriggerEvent('tdm:playerHit')
TriggerServerEvent('tdm:playerWasHit', currentGameId, currentTeam, lastDamager)
-- Warten um mehrfache Auslösung zu verhindern
Wait(500)
end
function checkGameEnd(gameId)
local game = activeGames[gameId]
if not game then return end
local totalPlayers = #game.team1 + #game.team2
if totalPlayers < 2 and game.status == 'active' then
debugPrint("Zu wenig Spieler - Beende Spiel " .. gameId)
endGame(gameId, nil, 'Zu wenig Spieler')
elseif totalPlayers == 0 then
activeGames[gameId] = nil
updateGamesListForAll()
debugPrint("Spiel " .. gameId .. " gelöscht (keine Spieler)")
else
Wait(500)
end
end
end)
function updateScoreForGame(gameId)
local game = activeGames[gameId]
if not game then
debugPrint("Score-Update fehlgeschlagen - Spiel nicht gefunden: " .. gameId)
return
-- Function to spawn NPCs for all fields
function spawnFieldNPCs()
for fieldId, fieldData in pairs(Config.gameFields) do
if fieldData.lobby and fieldData.lobby.npc then
local npcData = fieldData.lobby.npc
local model = GetHashKey(npcData.model)
-- Request the model
RequestModel(model)
while not HasModelLoaded(model) do
Wait(10)
end
debugPrint("Score Update für Spiel " .. gameId .. ": Team1=" .. game.score.team1 .. ", Team2=" .. game.score.team2)
-- Create the NPC
local npc = CreatePed(4, model, npcData.coords.x, npcData.coords.y, npcData.coords.z, npcData.coords.w, false, true)
SetEntityAsMissionEntity(npc, true, true)
SetBlockingOfNonTemporaryEvents(npc, true)
FreezeEntityPosition(npc, true)
SetEntityInvincible(npc, true)
for _, playerId in ipairs(game.team1) do
local playerStats = game.playerStats[playerId] or {hits = 0, deaths = 0}
TriggerClientEvent('tdm:updateScore', playerId, game.score.team1, game.score.team2, {
hits = playerStats.hits or 0,
deaths = playerStats.deaths or 0
-- Add to spawned NPCs table
table.insert(spawnedNPCs, npc)
-- Add target interaction
exports['qb-target']:AddTargetEntity(npc, {
options = {
{
type = "client",
event = "tdm:openMenu",
icon = "fas fa-gamepad",
label = "TeamDeathmatch Menu",
fieldId = fieldId
}
},
distance = 2.0
})
end
for _, playerId in ipairs(game.team2) do
local playerStats = game.playerStats[playerId] or {hits = 0, deaths = 0}
TriggerClientEvent('tdm:updateScore', playerId, game.score.team1, game.score.team2, {
hits = playerStats.hits or 0,
deaths = playerStats.deaths or 0
})
debugPrint("Spawned NPC for field: " .. fieldId)
end
end
end
function updateGamesListForAll()
local players = QBCore.Functions.GetPlayers()
for _, playerId in pairs(players) do
TriggerClientEvent('tdm:updateGamesList', playerId, activeGames)
end
end
-- Player Disconnect Handler
AddEventHandler('playerDropped', function()
local src = source
for gameId, game in pairs(activeGames) do
removePlayerFromGame(src, gameId)
end
debugPrint("Spieler " .. src .. " hat den Server verlassen - aus allen Spielen entfernt")
end)
-- Server Start - Games Liste leeren
AddEventHandler('onResourceStart', function(resourceName)
if GetCurrentResourceName() == resourceName then
activeGames = {}
gameIdCounter = 1
debugPrint("TeamDeathmatch System gestartet!")
-- Register event handler for NPC interaction
RegisterNetEvent('tdm:openMenu', function(data)
if data.fieldId then
openMainMenu(data.fieldId)
end
end)
-- Spawn NPCs when resource starts
CreateThread(function()
Wait(1000) -- Wait for everything to load
spawnFieldNPCs()
end)
-- Function to create blips for all TDM lobbies
function createTDMBlips()
for fieldId, fieldData in pairs(Config.gameFields) do
if fieldData.lobby and fieldData.lobby.pos then
local blip = AddBlipForCoord(fieldData.lobby.pos.x, fieldData.lobby.pos.y, fieldData.lobby.pos.z)
SetBlipSprite(blip, 156) -- You can change this to any appropriate sprite
SetBlipDisplay(blip, 4)
SetBlipScale(blip, 0.8)
SetBlipColour(blip, 3)
SetBlipAsShortRange(blip, true)
BeginTextCommandSetBlipName("STRING")
AddTextComponentString("TDM: " .. fieldData.name)
EndTextCommandSetBlipName(blip)
table.insert(tdmBlips, blip)
debugPrint("Created blip for TDM field: " .. fieldId)
end
end
end
-- Call this function when the resource starts
CreateThread(function()
Wait(2000) -- Wait for everything to load
createTDMBlips()
end)
-- Cleanup function
function cleanupResources()
-- Remove NPCs
for _, npc in ipairs(spawnedNPCs) do
if DoesEntityExist(npc) then
DeleteEntity(npc)
end
end
spawnedNPCs = {}
-- Remove blips
for _, blip in ipairs(tdmBlips) do
if DoesBlipExist(blip) then
RemoveBlip(blip)
end
end
tdmBlips = {}
debugPrint("Cleaned up all NPCs and blips")
end
-- Register cleanup when resource stops
AddEventHandler('onResourceStop', function(resourceName)
if GetCurrentResourceName() == resourceName then
-- Alle Spieler aus TDM entfernen
for gameId, game in pairs(activeGames) do
local allPlayers = {}
for _, playerId in ipairs(game.team1) do
table.insert(allPlayers, playerId)
end
for _, playerId in ipairs(game.team2) do
table.insert(allPlayers, playerId)
end
for _, playerId in ipairs(allPlayers) do
TriggerClientEvent('tdm:leaveGame', playerId)
end
end
activeGames = {}
debugPrint("TeamDeathmatch System gestoppt!")
cleanupResources()
end
end)
-- Admin-Befehle
RegisterCommand('tdmreset', function(source, args)
local src = source
if src > 0 then -- Spieler
local Player = QBCore.Functions.GetPlayer(src)
if not Player or not Player.PlayerData.job or Player.PlayerData.job.name ~= 'admin' then
TriggerClientEvent('QBCore:Notify', src, 'Du hast keine Berechtigung!', 'error')
return
end
end
-- Alle Spieler aus TDM entfernen
for gameId, game in pairs(activeGames) do
local allPlayers = {}
for _, playerId in ipairs(game.team1) do
table.insert(allPlayers, playerId)
end
for _, playerId in ipairs(game.team2) do
table.insert(allPlayers, playerId)
end
for _, playerId in ipairs(allPlayers) do
TriggerClientEvent('tdm:leaveGame', playerId)
end
end
activeGames = {}
gameIdCounter = 1
debugPrint("TeamDeathmatch System zurückgesetzt!")
if src > 0 then
TriggerClientEvent('QBCore:Notify', src, 'TDM System zurückgesetzt!', 'success')
end
end, true)
-- Debug-Befehl für Server-Status
RegisterCommand('tdmstatus', function(source, args)
local src = source
if src > 0 then -- Spieler
local Player = QBCore.Functions.GetPlayer(src)
if not Player or not Player.PlayerData.job or Player.PlayerData.job.name ~= 'admin' then
TriggerClientEvent('QBCore:Notify', src, 'Du hast keine Berechtigung!', 'error')
return
end
end
debugPrint("=== TDM STATUS ===")
debugPrint("Aktive Spiele: " .. table.count(activeGames))
for gameId, game in pairs(activeGames) do
debugPrint("Spiel: " .. gameId .. " - " .. game.name)
debugPrint(" Status: " .. game.status)
debugPrint(" Feld: " .. game.fieldId)
debugPrint(" Team 1: " .. #game.team1 .. " Spieler, Score: " .. game.score.team1)
debugPrint(" Team 2: " .. #game.team2 .. " Spieler, Score: " .. game.score.team2)
end
if src > 0 then
TriggerClientEvent('QBCore:Notify', src, 'TDM Status in Server-Konsole', 'info')
end
end, true)
-- Hilfsfunktion für table.count
-- Helper function for table.count
if not table.count then
table.count = function(tbl)
local count = 0
for _, _ in pairs(tbl) do
@ -1358,3 +976,4 @@ table.count = function(tbl)
end
return count
end
end

View file

@ -183,20 +183,19 @@ RegisterNetEvent('tdm:playerWasHit', function(gameId, victimTeam, attackerId)
game.playerStats[victim] = {hits = 0, deaths = 0}
end
if attackerId and not game.playerStats[attackerId] then
-- Wichtig: Nur wenn ein Angreifer identifiziert wurde, zähle den Kill
if attackerId then
if not game.playerStats[attackerId] then
game.playerStats[attackerId] = {hits = 0, deaths = 0}
end
-- Stats updaten
game.playerStats[victim].deaths = (game.playerStats[victim].deaths or 0) + 1
if attackerId then
game.playerStats[attackerId].hits = (game.playerStats[attackerId].hits or 0) + 1
-- Benachrichtigung an den Angreifer senden
TriggerClientEvent('tdm:hitRegistered', attackerId)
debugPrint("Treffer von " .. attackerId .. " gegen " .. victim .. " registriert")
else
debugPrint("Treffer gegen " .. victim .. " von unbekanntem Angreifer registriert")
end
-- Team Score erhöhen
if victimTeam == 'team1' then
@ -206,6 +205,9 @@ RegisterNetEvent('tdm:playerWasHit', function(gameId, victimTeam, attackerId)
game.score.team1 = game.score.team1 + 1
debugPrint("Punkt für Team 1 - Neuer Score: " .. game.score.team1)
end
else
debugPrint("Treffer gegen " .. victim .. " von unbekanntem Angreifer registriert - Kein Punkt vergeben")
end
TriggerClientEvent('tdm:deathRegistered', victim)