n
-- | Variables
local screenW, screenH = guiGetScreenSize()
local sx, sy = (screenW / 1920), (screenH / 1080)
local panelVisible = false
local topPlayers = {}
local alpha = 255
local sf_medium = dxCreateFont("SFPRODISPLAY_Medium.ttf", sx*20, false, "cleartype")
local interface = {}
-- | Dibujar el Panel de Estadísticas
function drawTopPanel()
--| Animations
if not interface["animations"]["general"]["outTick"] then
interface["animations"]["general"]["alpha"] = interpolateBetween(0, 0, 0, 255, 0, 0, (getTickCount() - interface["animations"]["general"]["tick"]) / 700, "OutQuad")
else
if not interface["animations"]["general"]["oldAlpha"] then
interface["animations"]["general"]["oldAlpha"] = interface["animations"]["general"]["alpha"]
end
if (getTickCount() - interface["animations"]["general"]["outTick"]) >= 400 then
closeHelp()
end
interface["animations"]["general"]["alpha"] = interpolateBetween(interface["animations"]["general"]["oldAlpha"], 0, 0, 0, 0, 0, (getTickCount() - interface["animations"]["general"]["outTick"]) / 700, "OutQuad")
end
local alpha = interface["animations"]["general"]["alpha"]
-- Fondo con bordes redondeados
dxDrawRoundedRectangle(478, 197, 964, 800, tocolor(33, 35, 38, (alpha/100)*98), 15, false)
-- Icono y Título
dxDrawImage(531, 245, 28, 28, Images["icon: death"], 0, 0, 0, tocolor(111,0,255, alpha))
dxDrawText("TOP JUGADORES", 576, 240, 100, 22, tocolor(255, 255, 255, (alpha/100)*85), 0.66, sf_medium, "left", "top")
dxDrawText("Ranking de los mejores jugadores por Kills, Deaths y K/D Ratio", 576, 259.94, 332, 19, tocolor(255, 255, 255, (alpha/100)*25), 0.5, sf_medium, "left", "top")
-- Botón de Cerrar (X)
dxDrawImage(1367, 245, 21, 21, Images["icon: exit"], 0, 0, 0, (isCursorOnElement(1367, 245, 21, 21) and tocolor(255, 255, 255, (alpha/100)*25) or tocolor(255, 255, 255, (alpha/100)*15)), false)
-- Botones de navegación
-- Global
dxDrawImage(531, 307, 21, 21, Images["icon: kill"], 0, 0, 0, (interface["page"] == "global" and tocolor(111,0,255, alpha) or (isCursorOnElement(531, 307, 77, 21) and tocolor(255, 255, 255, (alpha/100)*25) or tocolor(255, 255, 255, (alpha/100)*15))), false)
dxDrawText("Global", 557, 307, 51, 18, (interface["page"] == "global" and tocolor(111,0,255, alpha) or (isCursorOnElement(531, 307, 77, 21) and tocolor(255, 255, 255, (alpha/100)*25) or tocolor(255, 255, 255, (alpha/100)*15))), 0.59, sf_medium, "left", "top")
-- Zona Roja
dxDrawImage(627, 307, 21, 21, Images["icon: kill"], 0, 0, 0, (interface["page"] == "roja" and tocolor(111,0,255, alpha) or (isCursorOnElement(627, 307, 73, 21) and tocolor(255, 255, 255, (alpha/100)*25) or tocolor(255, 255, 255, (alpha/100)*15))), false)
dxDrawText("Zona Roja", 653, 307, 47, 18, (interface["page"] == "roja" and tocolor(111,0,255, alpha) or (isCursorOnElement(627, 307, 73, 21) and tocolor(255, 255, 255, (alpha/100)*25) or tocolor(255, 255, 255, (alpha/100)*15))), 0.59, sf_medium, "left", "top")
-- Mostrar contenido según la pestaña seleccionada
if interface["page"] == "global" then
-- Dibujar encabezados de la tabla
dxDrawText("Rank", 530, 350, 570, 280, tocolor(255, 215, 0, alpha), 0.7, "default-bold")
dxDrawText("Nick", 590, 350, 750, 280, tocolor(255, 255, 255, alpha), 0.7, "default-bold")
dxDrawText("Acoounts", 690, 350, 850, 280, tocolor(255, 255, 255, alpha), 0.7, "default-bold")
dxDrawText("Kills", 800, 350, 960, 280, tocolor(255, 255, 255, alpha), 0.7, "default-bold")
dxDrawText("Deaths", 890, 350, 1050, 280, tocolor(255, 255, 255, alpha), 0.7, "default-bold")
dxDrawText("K/D", 970, 350, 1140, 280, tocolor(255, 255, 255, alpha), 0.7, "default-bold")
dxDrawText("Level", 1040, 350, 1230, 280, tocolor(255, 255, 255, alpha), 0.7, "default-bold")
dxDrawText("Status", 1100, 350, 1320, 280, tocolor(255, 255, 255, alpha), 0.7, "default-bold")
-- Dibujar filas de la tabla
for i, player in ipairs(topPlayers) do
if player.rank and player.nick and player.account and player.kills and player.deaths and player.kdr and player.level then
local y = 370 + (i * 30) -- Posición vertical de cada jugador
-- Verificar si el jugador está conectado (online)
local status = "Offline" -- Por defecto, se asume que está offline
local onlinePlayer = getPlayerFromName(player.nick)
if onlinePlayer then
status = "Online"
end
-- Definir el color dependiendo del estado
local statusColor = (status == "Online") and tocolor(0, 255, 0, alpha) or tocolor(255, 0, 0, alpha)
-- Dibujar los textos en la interfaz
dxDrawText(player.rank .. "°", 535, y, 650, 280, tocolor(255, 255, 255, alpha), 0.7, "default-bold") -- Rango del jugador
dxDrawText(player.nick, 590, y, 750, 280, tocolor(255, 255, 255, alpha), 0.7, "default-bold") -- Kills
dxDrawText(player.account, 690, y, 850, 280, tocolor(255, 255, 255, alpha), 0.7, "default-bold") -- Deaths
dxDrawText(player.kills, 800, y, 950, 280, tocolor(255, 255, 255, alpha), 0.7, "default-bold") -- K/D Ratio
dxDrawText(player.deaths, 890, y, 1050, 280, tocolor(255, 255, 255, alpha), 0.7, "default-bold") -- K/D Ratio
dxDrawText(player.kdr, 970, y, 1150, 280, tocolor(255, 255, 255, alpha), 0.7, "default-bold") -- K/D Ratio
dxDrawText(player.level, 1040, y, 1250, 280, tocolor(255, 255, 255, alpha), 0.7, "default-bold") -- K/D Ratio
dxDrawText(status, 1100, y, 1350, 280, statusColor, 0.7, "default-bold") -- K/D Ratio
end
end
elseif interface["page"] == "roja" then
dxDrawText("Top", 535, 350, 570, 280, tocolor(255, 215, 0, alpha), 0.7, "default-bold")
dxDrawText("User", 590, 350, 750, 280, tocolor(255, 255, 255, alpha), 0.7, "default-bold")
dxDrawText("Kills", 780, 350, 850, 280, tocolor(255, 255, 255, alpha), 0.7, "default-bold")
dxDrawText("Deaths", 880, 350, 960, 280, tocolor(255, 255, 255, alpha), 0.7, "default-bold")
dxDrawText("K/D", 980, 350, 1050, 280, tocolor(255, 255, 255, alpha), 0.7, "default-bold")
end
--| Scroll
-- dxDrawRoundedRectangle(1009, 439, 6, 378, tocolor(255, 255, 255, (alpha/100)*2), 3, false)
-- interface["scroll"]["smooth"] = interpolateBetween(interface["scroll"]["oldPos"], 0, 0, interface["scroll"]["newPos"], 0, 0, (getTickCount() - interface["scroll"]["tick"]) / 400, "OutQuad")
-- dxDrawRoundedRectangle(1009, interface["scroll"]["smooth"], 6, 146.91, tocolor(111,0,255, alpha), 2.5, false)
end
function openHelp()
if not isEventHandlerAdded('onClientRender', root, drawTopPanel) then
interface = {
animations = {
general = {
alpha = 0,
tick = getTickCount(),
},
nav = {
tick = getTickCount(),
oldPos = 549,
newPos = 549,
},
},
page = "global",
scroll = {
data = 0,
tick = getTickCount(),
oldPos = 439,
newPos = 439,
},
}
addEventHandler('onClientRender', root, drawTopPanel)
showCursor(true)
showChat(false)
triggerServerEvent("requestTopStats", localPlayer)
end
end
addEvent("FS:openHelp", true)
addEventHandler("FS:openHelp", root, drawTopPanel)
function closeHelp()
if isEventHandlerAdded('onClientRender', root, drawTopPanel) then
if not interface["animations"]["general"]["outTick"] then
interface["animations"]["general"]["outTick"] = getTickCount()
return
end
removeEventHandler('onClientRender', root, drawTopPanel)
showCursor(false)
showChat(true)
end
end
function toggleProducts()
if isEventHandlerAdded('onClientRender', root, drawTopPanel) then
closeHelp()
else
openHelp()
end
end
bindKey("F2", "down", toggleProducts)
function closeHelp()
if isEventHandlerAdded('onClientRender', root, drawTopPanel) then
if not interface["animations"]["general"]["outTick"] then
interface["animations"]["general"]["outTick"] = getTickCount()
return
end
removeEventHandler('onClientRender', root, drawTopPanel)
showCursor(false)
showChat(true)
end
end
--| Scroll
function scrollItens(button)
if isEventHandlerAdded('onClientRender', root, renderHelp) then
local data = (interface["scroll"]["data"] or 0)
if (button == "mouse_wheel_up") and (data > 0) then
data = (data - 1)
elseif (button == "mouse_wheel_down") and (data < (#config["help"][ interface["page"] ]["itens"] - 5)) then
data = (data + 1)
end
interface["scroll"]["data"], interface["scroll"]["oldPos"], interface["scroll"]["newPos"], interface["scroll"]["tick"] = data, interface["scroll"]["smooth"], (439 + (231/(#config["help"][ interface["page"] ]["itens"] - 5)*data)), getTickCount()
end
end
bindKey("mouse_wheel_up", "down", scrollItens)
bindKey("mouse_wheel_down", "down", scrollItens)
addEventHandler("onClientClick", root, function(button, state)
if isEventHandlerAdded('onClientRender', root, drawTopPanel) then
if (button == "left") and (state == "down") then
--| Close panel
if isCursorOnElement(1367, 245, 21, 21) then
closeHelp()
--| Navegation
elseif isCursorOnElement(531, 307, 77, 21) then
interface["page"] = "global"
interface["animations"]["nav"]["oldPos"], interface["animations"]["nav"]["newPos"], interface["animations"]["nav"]["tick"] = interface["animations"]["nav"]["smooth"], 549, getTickCount()
--interface["scroll"]["data"], interface["scroll"]["oldPos"], interface["scroll"]["newPos"], interface["scroll"]["tick"] = data, interface["scroll"]["smooth"], (439 + (231/(#topPlayers - 5)*0)), getTickCount()
elseif isCursorOnElement(627, 307, 73, 21) then
interface["page"] = "roja"
interface["animations"]["nav"]["oldPos"], interface["animations"]["nav"]["newPos"], interface["animations"]["nav"]["tick"] = interface["animations"]["nav"]["smooth"], 653, getTickCount()
-- interface["scroll"]["data"], interface["scroll"]["oldPos"], interface["scroll"]["newPos"], interface["scroll"]["tick"] = data, interface["scroll"]["smooth"], (439 + (231/(#config["help"][ interface["page"] ]["itens"] - 5)*0)), getTickCount()
end
end
end
end)
-- | Cerrar panel con clic en "X"
client.lua
addEventHandler("onClientClick", root, function(button, state)
if panelVisible and button == "left" and state == "down" then
if isCursorOnElement(1150, 190, 21, 21) then
toggleTopPanel()
end
end
end)
addEvent("updateTopStats", true)
addEventHandler("updateTopStats", root, function(data)
topPlayers = data or {} -- Guarda la lista de jugadores recibida del servidor
end)
local lastWeekday = getRealTime().weekday -- não mexa
local updatePlayersDataTime = 5 -- atualizar a cada 5 minutos
local tableInsert = table.insert
local tableSort = table.sort
function recebeKills ( thePlayer )
local thePlayer = client or thePlayer
local data = getAccounts ()
local playerData = {}
local playerData2 = {}
local dmKills = {}
local kill = 0
local death = 0
local killsTemp = 0
local deathsTemp = 0
for i, acc in ipairs(data) do
kill, death = tonumber(getAccountData (acc, "kills") or 0), tonumber(getAccountData (acc, "deaths") or 0)
killsTemp, deathsTemp = tonumber(getAccountData (acc, "killsTemp") or 0), tonumber(getAccountData (acc, "deathsTemp") or 0)
local DMKill, DMDeath = 0, 0
local status, nick, level = "Offline", "", "N/A"
if getAccountPlayer(acc) then
local p = getAccountPlayer(acc)
level = getElementData(p, "level") or 1
status = "Online"
nick = getElementData( p, "player-lastnick" ) or getPlayerName(p)
--level = getElementData(p, 'Level') or "N/A"
DMKill = getElementData(p, 'DMKill') or 0
DMDeath = getElementData(p, 'DMDeath') or 0
else
nick = getAccountData( acc, "player-lastnick" ) or "?"
level = getAccountData( acc, "level" ) or 1
--level = getAccountData(acc, 'Level') or "N/A"
DMKill = getAccountData(acc, 'DMKill') or 0
DMDeath = getAccountData(acc, 'DMDeath') or 0
end
local ratio = kill / death
if death == 0 and kill == 0 then -- Se ambos os valores forem 0, deixa o ratio em 0 também.
ratio = 0
elseif kill ~= 0 and death == 0 then -- Se death for 0 mas kill não, deixa o ratio como Desconocido, pois não é possível dividir algo por 0.
ratio = "?"
end
local ratioTemp = killsTemp / deathsTemp
if deathsTemp == 0 and killsTemp == 0 then -- Se ambos os valores forem 0, deixa o ratio em 0 também.
ratioTemp = 0
elseif killsTemp ~= 0 and deathsTemp == 0 then -- Se death for 0 mas kill não, deixa o ratio como Desconocido, pois não é possível dividir algo por 0.
ratioTemp = "?"
end
tableInsert( playerData,
{
{ nick:gsub("#%x%x%x%x%x%x", ""), getAccountName(acc), status }, kill, death, ratio, killsTemp, deathsTemp, ratioTemp,
level = level
}
)
tableInsert(dmKills, {
{ nick:gsub("#%x%x%x%x%x%x", ""), getAccountName(acc), status }, kill, death, ratio, killsTemp, deathsTemp, ratioTemp,
level = level, DMKill = DMKill, DMDeath = DMDeath
})
end
for i,v in pairs(playerData) do
playerData2[ #playerData2 + 1 ] = { v[1], v[5], v[6], v[7], level = v.level or "1" }
end
tableSort( playerData, function(a, b) return a[2] > b[2] end )
tableSort( playerData2, function(a, b) return a[2] > b[2] end )
tableSort( dmKills, function(a, b) return a.DMKill > b.DMKill end )
if #playerData > 100 then
for i=101, #playerData do
playerData[i] = nil
end
end
if #playerData2 > 100 then
for i=101, #playerData2 do
playerData2[i] = nil
end
end
if #dmKills > 100 then
for i=101, #dmKills do
dmKills[i] = nil
end
end
--triggerClientEvent (thePlayer, "showRank", thePlayer, playerData, playerData2, dmKills)
end
addEvent ("getRank", true)
addEventHandler ("getRank", getRootElement(), recebeKills)
function salvaKills (ammo, killer, weapon, bodypart, stealth)
if not isGuestAccount (getPlayerAccount(source)) then
local deaths = tonumber( getAccountData (getPlayerAccount(source), "deaths") or 0 )
local deathsTemp = tonumber( getAccountData (getPlayerAccount(source), "deathsTemp") or 0 )
setAccountData (getPlayerAccount(source), "deaths", deaths + 1)
setAccountData (getPlayerAccount(source), "deathsTemp", deathsTemp + 1)
end
if killer and killer ~= source then
if getElementType (killer) == "player" then
if not isGuestAccount (getPlayerAccount(killer)) then
local kills = tonumber( getAccountData (getPlayerAccount(killer), "kills") or 0 )
local killsTemp = tonumber( getAccountData (getPlayerAccount(killer), "killsTemp") or 0 )
setAccountData (getPlayerAccount(killer), "kills", kills + 1)
setAccountData (getPlayerAccount(killer), "killsTemp", killsTemp + 1)
end
elseif getElementType (killer) == "vehicle" then
killer = getVehicleController (killer)
if killer then
if not isGuestAccount (getPlayerAccount(killer)) then
local kills = tonumber( getAccountData (getPlayerAccount(killer), "kills") or 0 )
local killsTemp = tonumber( getAccountData (getPlayerAccount(killer), "killsTemp") or 0 )
setAccountData (getPlayerAccount(killer), "kills", kills + 1)
setAccountData (getPlayerAccount(killer), "killsTemp", killsTemp + 1)
end
end
end
end
end
addEventHandler ("onPlayerWasted", getRootElement(), salvaKills)
function checkWeeklyRank ()
if getRealTime().weekday == 0 and (lastWeekday == 6) then
resetWeeklyKillsData ()
lastWeekday = getRealTime().weekday
else
lastWeekday = getRealTime().weekday
end
end
addEventHandler ("onResourceStart", resourceRoot, function ()
setTimer (function ()
for i, player in pairs(getElementsByType("player")) do
recebeKills (player)
end
end, 2000, 1)
setTimer (function ()
checkWeeklyRank ()
end, 60000 * updatePlayersDataTime, 0)
end)
function resetWeeklyKillsData ()
local now = getRealTime() -- Recebe os dados do momento atual.
local hours = now.hour
local minutes = now.minute
local days = now.monthday
local months = now.month
local years = now.year
for i, acc in pairs(getAccounts()) do
if getAccountData(acc, "killsTemp") then
setAccountData(acc, "killsTemp", 0)
end
if getAccountData(acc, "deathsTemp") then
setAccountData(acc, "deathsTemp", 0)
end
end
local dateUpdate = string.format( "%02d/%02d/%02d", tostring(days),tostring(months + 1),tostring(years + 1900) )
local timeUpdate = string.format( "%02d:%02d", tostring(hours),tostring(minutes) )
print ("[RankSystem] Rank semanal resetado!")
print ("[RankSystem] Data: "..dateUpdate)
print ("[RankSystem] Hora: "..timeUpdate)
end
function getAccountRank( acc, weekly )
if not (acc) then return false end
local accDataStr = weekly and "killsTemp" or "kills"
local accsRank = {}
local accounts = getAccounts ()
for _, accnt in ipairs(accounts) do
local kills = tonumber(getAccountData (accnt, accDataStr) or 0)
tableInsert( accsRank, { accnt, kills } )
end
tableSort( accsRank, function(a, b) return a[2] > b[2] end )
for i, t in ipairs(accsRank) do
if acc == t[1] then
return i
end
end
return false
end
function getPlayerFromPartialName(name)
local name = name and name:gsub("#%x%x%x%x%x%x", ""):lower() or nil
if name then
for _, player in ipairs(getElementsByType("player")) do
local name_ = getPlayerName(player):gsub("#%x%x%x%x%x%x", ""):lower()
if name_:find(name, 1, true) then
return player
end
end
end
end
function math.round(number, decimals, method)
if number and type(number) == "number" then
decimals = decimals or 0
local factor = 10 ^ decimals
if (method == "ceil" or method == "floor") then
return math[method](number * factor) / factor
else
return tonumber(("%."..decimals.."f"):format(number))
end
end
return 0
end
-- | Base de datos de jugadores (Ejemplo, reemplázalo con tu BD real)
local playerStats = {}
-- | Función para obtener estadísticas y enviarlas al cliente
-- Evento para manejar la solicitud de estadísticas del cliente
addEvent("requestTopStats", true) -- Definimos el evento
addEventHandler("requestTopStats", root, function()
sendTopStats(source) -- Llamamos a la función para enviar las estadísticas al jugador que lo solicita
end)
function sendTopStats(player)
local topData = {}
-- Obtener todas las cuentas registradas
local accounts = getAccounts() -- Asegúrate de que esta función devuelve una lista válida de cuentas registradas
local maxPlayers = 20 -- Limitar a 20 jugadores
for _, account in ipairs(accounts) do
if account and not isGuestAccount(account) then
-- Verifica si la cuenta no es nula antes de proceder
local accountName = getAccountName(account)
if accountName then
local Levels = tostring (getAccountData(account,"Level") or "0")
-- local Levels = getAccountSerial(account)
local nicks = getAccountName(account)
local kills = tostring(getAccountData(account, "kills") or "0")
local deaths = tostring(getAccountData(account, "deaths") or "0")
local killsTemp = tostring(getAccountData(account, "killsTemp") or "0")
local deathsTemp = tostring(getAccountData(account, "deathsTemp") or "0")
local ratio = kills / deaths
local ratioTemp = killsTemp / deathsTemp
local killsrank = getAccountRank(account) or "Desconocido"
local killsrankTemp = getAccountRank(account, true) or "Desconocido"
-- Manejo de división por cero en el ratio
if tonumber(deaths) == 0 and tonumber(kills) == 0 then
ratio = "0"
elseif tonumber(kills) ~= 0 and tonumber(deaths) == 0 then
ratio = "Desconocido"
end
if tonumber(deathsTemp) == 0 and tonumber(killsTemp) == 0 then
ratioTemp = 0
elseif tonumber(killsTemp) ~= 0 and tonumber(deathsTemp) == 0 then
ratioTemp = "Desconocido"
end
-- Agregar el ranking con el sufijo de posición
if killsrank ~= "Desconocido" then
killsrank = tostring(killsrank) .. "º"
end
if killsrankTemp ~= "Desconocido" then
killsrankTemp = tostring(killsrankTemp) .. "º"
end
-- Redondear los ratios
if ratio ~= "Desconocido" then
ratio = tostring(math.round(tonumber(ratio), 2, "floor"))
end
if ratioTemp ~= "0/0" then
ratioTemp = tostring(math.round(tonumber(ratioTemp), 2, "floor"))
end
-- Insertar los datos en la tabla
table.insert(topData, {
rank = killsrankTemp,
nick = nicks,
account = accountName, -- Nombre de la cuenta
kills = killsTemp,
deaths = deathsTemp,
kdr = ratioTemp,
level = Levels,
})
if #topData >= maxPlayers then
break
end
end
end
end
-- Ordenamos los datos por kills (mayor a menor)
table.sort(topData, function(a, b) return a.kills > b.kills end)
-- Enviamos los datos al cliente
triggerClientEvent(player, "updateTopStats", player, topData)
end
lo que pasa que en mi codigo puse el rango que esta en el server.lua , pero cuando lo pongo en el client su rango player.rank sale desordenado