Olá pessoal aqui da comunidade, ja estou batendo cabeça aqui sobre um sistema de caça de pk ou hunted sistem ja faz quase uma semana recorrendo a todos os forums e sem sucesso, ja vi que tem aqui um post sobre este sistema , ja tentei por em pratica ele mas sem sucesso. pois a versão que estou é a 13x e os codigos não funciona na minha versão, tentei por diversas vezes fazer as modificações trazendo para o client mais atual mas nada...
Alguem por gentileza tem algo ja funcionando nesta versão e que possa compartilhar?
Volto a repetir, ja vi varios aqui mas tudo nas versoes antigas, que não esta dando certo para minha versão mais recente.
cheguei ate este ponto aqui, mas daqui ja não estou conseguindo progredir... é erro atras de erro...
segue a criação da tabela de banco do banco de dados:
CREATE TABLE `busque_cabeca` (
`id` INT AUTO_INCREMENT PRIMARY KEY, -- ID único para cada entrada
`fp_id` INT NOT NULL, -- ID do jogador que ofereceu a recompensa
`sp_id` INT NOT NULL, -- ID do jogador caçado
`k_id` INT DEFAULT 0, -- ID do jogador que matou o alvo (0 se ainda vivo)
`added` INT NOT NULL, -- Timestamp de quando a recompensa foi adicionada
`prize` BIGINT NOT NULL, -- Valor total da recompensa
`fp_ids` TEXT, -- Lista de IDs dos jogadores que contribuíram para a recompensa
`killed` TINYINT DEFAULT 0, -- Status: 0 = vivo, 1 = morto
`kill_time` INT DEFAULT 0 -- Timestamp de quando o jogador foi morto
);
SEGUE O CODIGO .LUA
-- Definição das constantes de mensagem (ajuste conforme necessário)
local MESSAGE_STATUS_CONSOLE_BLUE = 17
local MESSAGE_STATUS_CONSOLE_ORANGE = 18
-- Função auxiliar para dividir strings
function string:split(sep)
local fields = {}
local pattern = string.format("([^%s]+)", sep)
self:gsub(pattern, function(c) fields[#fields + 1] = c end)
return fields
end
-- Função para obter o GUID do jogador pelo nome
function getPlayerGUIDByName(name)
print("[DEBUG] getPlayerGUIDByName called for name: " .. name)
local resultId = db.storeQuery("SELECT `id` FROM `players` WHERE `name` = " .. db.escapeString(name))
if not resultId then
print("[DEBUG] Player not found in database.")
return nil
end
local guid = result.getNumber(resultId, "id")
result.free(resultId)
print("[DEBUG] Found player GUID: " .. guid)
return guid
end
-- Função para verificar o dinheiro total do jogador (em mãos + banco)
function getPlayerTotalMoney(player)
local moneyInHand = player:getMoney()
local bankBalance = player:getBankBalance()
print("[DEBUG] Money in hand: " .. moneyInHand .. ", Bank balance: " .. bankBalance)
return moneyInHand + bankBalance
end
-- Função para remover dinheiro total do jogador (priorizando o banco)
function removePlayerTotalMoney(player, amount)
local moneyInHand = player:getMoney()
local bankBalance = player:getBankBalance()
if bankBalance >= amount then
-- Retira todo o valor do banco
player:setBankBalance(bankBalance - amount)
print("[DEBUG] Removed " .. amount .. " coins from bank.")
else
-- Retira o que puder do banco e o restante da bag
local remainingAmount = amount - bankBalance
player:setBankBalance(0)
if moneyInHand >= remainingAmount then
player:removeMoney(remainingAmount)
print("[DEBUG] Removed " .. bankBalance .. " coins from bank and " .. remainingAmount .. " coins from hand.")
else
print("[DEBUG] Insufficient funds after attempting to remove money.")
return false
end
end
return true
end
-- Comando !busque
local busque = TalkAction("!busque")
busque:separator(" ")
function busque.onSay(player, words, param)
print("[DEBUG] !busque called by player: " .. player:getName())
local t = param:split(" ")
if #t < 2 then
print("[DEBUG] Insufficient parameters provided.")
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "[BUSQUE A CABEÇA] Use: \"!busque [valor] [nick]\" Exemplo de prêmio: 1(k).")
return true
end
local prize = tonumber(t[1])
local targetName = t[2]
print("[DEBUG] Prize: " .. tostring(prize) .. ", Target Name: " .. targetName)
if not prize or prize < 1 or prize >= 100000000000000000000 then
print("[DEBUG] Invalid prize value.")
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "[BUSQUE A CABEÇA] Valor de prêmio inválido.")
return true
end
local sp_id = getPlayerGUIDByName(targetName)
if not sp_id then
print("[DEBUG] Target player does not exist.")
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "[BUSQUE A CABEÇA] Este jogador não existe.")
return true
end
if sp_id == player:getGuid() then
print("[DEBUG] Player tried to add themselves to the list.")
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "[BUSQUE A CABEÇA] Você não pode colocar a si mesmo na lista de caçados.")
return true
end
local totalMoney = getPlayerTotalMoney(player)
print("[DEBUG] Total money available: " .. totalMoney .. ", Required amount: " .. prize)
if totalMoney < prize then
print("[DEBUG] Player does not have enough money.")
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "[BUSQUE A CABEÇA] Você não tem dinheiro suficiente.")
return true
end
-- Verifica se o jogador já está na lista de caçados
local result_plr = db.storeQuery("SELECT `id`, `prize`, `fp_ids` FROM `busque_cabeca` WHERE `sp_id` = " .. sp_id .. " AND `killed` = 0;")
if result_plr then
-- Jogador já está na lista, verifica se o jogador atual já fez uma oferta
local id = result.getNumber(result_plr, "id")
local currentPrize = result.getNumber(result_plr, "prize")
local fp_ids = result.getString(result_plr, "fp_ids") or ""
result.free(result_plr)
print("[DEBUG] Current prize: " .. currentPrize)
print("[DEBUG] Current fp_ids: " .. fp_ids)
-- Verifica se o jogador atual já fez uma oferta
local fp_id = player:getGuid()
if fp_ids:find(tostring(fp_id)) then
print("[DEBUG] Player already made an offer for this target.")
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "[BUSQUE A CABEÇA] Você já fez uma oferta para este jogador.")
return true
end
-- Acumula o valor da recompensa e atualiza a lista de IDs
local newPrize = currentPrize + prize
local updatedFpIds = fp_ids .. (fp_ids == "" and "" or ",") .. fp_id
print("[DEBUG] Updated prize: " .. newPrize)
print("[DEBUG] Updated fp_ids: " .. updatedFpIds)
local updateQuery = string.format(
"UPDATE `busque_cabeca` SET `prize` = %d, `fp_ids` = '%s' WHERE `id` = %d;",
newPrize, updatedFpIds, id
)
db.asyncQuery(updateQuery)
print("[DEBUG] Bounty updated for player ID: " .. sp_id .. ". New prize: " .. newPrize)
-- Remove o dinheiro do jogador
if not removePlayerTotalMoney(player, prize) then
print("[DEBUG] Failed to remove money from player.")
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "[BUSQUE A CABEÇA] Erro ao processar o pagamento. Tente novamente.")
return true
end
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "[BUSQUE A CABEÇA] Recompensa acumulada! Novo valor total: " .. newPrize .. " moedas.")
return true
end
-- Jogador não está na lista, cria uma nova entrada
local query = string.format(
"INSERT INTO `busque_cabeca` (`fp_id`, `sp_id`, `k_id`, `added`, `prize`, `fp_ids`, `killed`, `kill_time`) VALUES (%d, %d, 0, %d, %d, '%d', 0, 0);",
player:getGuid(), sp_id, os.time(), prize, player:getGuid()
)
db.asyncQuery(query)
print("[DEBUG] Bounty added successfully for player ID: " .. sp_id)
-- Remove o dinheiro do jogador
if not removePlayerTotalMoney(player, prize) then
print("[DEBUG] Failed to remove money from player.")
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "[BUSQUE A CABEÇA] Erro ao processar o pagamento. Tente novamente.")
return true
end
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "[BUSQUE A CABEÇA] Mandato de caçada criado com sucesso!")
end
-- Registra o comando !busque
busque:groupType("normal") -- Permite apenas jogadores do grupo "normal" a usar o comando
busque:register()
-- Função para processar a morte do jogador
function processPlayerDeath(playerId, killed_by)
print("[DEBUG] Processing death for player ID: " .. playerId .. ", Killed by: " .. killed_by)
-- Consulta o banco de dados para verificar se o jogador está na lista de caçados
local result_plr = db.storeQuery("SELECT `id`, `prize`, `killed` FROM `busque_cabeca` WHERE `sp_id` = " .. playerId .. " AND `killed` = 0;")
if not result_plr then
print("[DEBUG] Player is not on the bounty list.")
return true
end
local id = result.getNumber(result_plr, "id")
local prize = result.getNumber(result_plr, "prize")
local killed = result.getNumber(result_plr, "killed")
result.free(result_plr)
print("[DEBUG] Player is on the bounty list. ID: " .. id .. ", Prize: " .. prize .. ", Killed: " .. killed)
-- Obtém o ID do assassino pelo nome
local killer_id = getPlayerGUIDByName(killed_by)
if not killer_id then
print("[DEBUG] Failed to retrieve killer ID.")
return true
end
print("[DEBUG] Killer ID: " .. killer_id)
-- Atualiza o banco de dados para marcar o jogador como morto
local updateQuery = string.format(
"UPDATE `busque_cabeca` SET `k_id` = %d, `killed` = 1, `kill_time` = %d WHERE `id` = %d;",
killer_id, os.time(), id
)
db.asyncQuery(updateQuery)
print("[DEBUG] Player marked as killed in database. ID: " .. id)
-- Obtém o objeto do assassino
local killer = Player(killer_id)
if not killer then
print("[DEBUG] Killer player object not found.")
return true
end
-- Deposita o prêmio diretamente no banco do assassino
local currentBankBalance = killer:getBankBalance()
killer:setBankBalance(currentBankBalance + prize)
print("[DEBUG] Awarded " .. prize .. " coins to killer's bank account: " .. killer:getName())
killer:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "[BUSQUE A CABEÇA] Você recebeu " .. prize .. " moedas no seu banco por matar este jogador!")
-- Mensagem para o assassino informando que o alvo foi marcado como inativo
killer:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "[BUSQUE A CABEÇA] O jogador " .. getPlayerNameById(playerId) .. " foi removido da lista de caçados.")
return true
end
-- Função auxiliar para obter o nome do jogador pelo ID
function getPlayerNameById(playerId)
local resultId = db.storeQuery("SELECT `name` FROM `players` WHERE `id` = " .. playerId)
if not resultId then
return "Unknown"
end
local name = result.getString(resultId, "name")
result.free(resultId)
return name
end
-- Função principal para verificar mortes periodicamente
function checkForDeaths()
print("[DEBUG] Checking for recent deaths...")
-- Determina o formato do campo `time` e ajusta a consulta SQL
local query
if isUnixTimestampFormat() then
-- Caso 1: `time` é armazenado em segundos desde a época Unix
query = "SELECT `player_id`, `killed_by`, `is_player` FROM `player_deaths` WHERE `time` > UNIX_TIMESTAMP() - 60;"
elseif isDatetimeFormat() then
-- Caso 2: `time` é armazenado no formato MySQL (`DATETIME` ou `TIMESTAMP`)
query = "SELECT `player_id`, `killed_by`, `is_player` FROM `player_deaths` WHERE `time` > NOW() - INTERVAL 60 SECOND;"
else
-- Caso 3: Formato personalizado (ajuste conforme necessário)
print("[DEBUG] Unknown `time` format in `player_deaths`. Cannot process deaths.")
return true
end
print("[DEBUG] Executing query: " .. query)
local result = db.storeQuery(query)
if not result then
print("[DEBUG] No recent deaths found or query failed.")
return true
end
-- Verifica se o resultado é válido antes de iterar
if type(result) ~= "userdata" then
print("[DEBUG] Invalid result type returned by db.storeQuery: " .. type(result))
return true
end
-- Verifica se há linhas no resultado
if not result.next(result) then
print("[DEBUG] Query returned no rows.")
result.free(result)
return true
end
-- Itera sobre os resultados da consulta
repeat
local playerId = result.getNumber(result, "player_id")
local killedBy = result.getString(result, "killed_by")
local isPlayer = result.getNumber(result, "is_player")
if playerId then
print("[DEBUG] Found recent death for player ID: " .. playerId)
if killedBy and isPlayer == 1 then
print("[DEBUG] Player was killed by: " .. killedBy)
processPlayerDeath(playerId, killedBy)
else
print("[DEBUG] Killer is not a player or data is invalid.")
end
else
print("[DEBUG] Invalid player ID found in death records.")
end
until not result.next(result)
-- Libera o resultado para evitar vazamentos de memória
if result.free then
result.free(result)
print("[DEBUG] Result freed successfully.")
else
print("[DEBUG] Result object does not have a 'free' method.")
end
return true
end
-- Função para verificar o formato do campo `time`
function isUnixTimestampFormat()
local result = db.storeQuery("SELECT `time` FROM `player_deaths` LIMIT 1;")
if not result then
return false
end
local timeValue = result.getNumber(result, "time")
result.free(result)
-- Verifica se o valor é um número inteiro
return type(timeValue) == "number" and math.floor(timeValue) == timeValue
end
function isDatetimeFormat()
local result = db.storeQuery("SELECT `time` FROM `player_deaths` LIMIT 1;")
if not result then
return false
end
local timeValue = result.getString(result, "time")
result.free(result)
-- Verifica se o valor é uma string no formato `YYYY-MM-DD HH:MM:SS`
return type(timeValue) == "string" and timeValue:match("%d%d%d%d%-%d%d%-%d%d %d%d:%d%d:%d%d")
end
-- Registra a verificação de mortes como um evento periódico
local deathCheckEvent = GlobalEvent("death_check_event")
function deathCheckEvent.onThink(interval)
checkForDeaths()
return true
end
deathCheckEvent:interval(60000) -- Executa a cada 60 segundos
deathCheckEvent:register()
Se alguem tiver alguma sulução para me ajudar pois realmente estou a desistir ja.
Estes são os erros.....
Interface: Scripts Interface
Script ID: C:\otserv\data/scripts\talkactions\player\busque.lua:callback
Error Description: C:\otserv\data/scripts\talkactions\player\busque.lua:311: attempt to index local 'result' (a number value)
stack traceback:
[C]: in function '__index'
C:\otserv\data/scripts\talkactions\player\busque.lua:311: in function 'isUnixTimestampFormat'
C:\otserv\data/scripts\talkactions\player\busque.lua:241: in function 'checkForDeaths'
C:\otserv\data/scripts\talkactions\player\busque.lua:334: in function <C:\otserv\data/scripts\talkactions\player\busque.lua:333>
---------------------------------------
[2025-03-02 20:05:11.708] [error] [GlobalEvents::think] - Failed to execute event: death_check_event
Vamos lá só resumindo aqui...
o que esta funcionando:
- char usa o comando !busque (valor a ser pago) (nome do personagem)
- Não permite o mesmo player colocar mais que uma vez a oferta.. mas deixa outros jogadores colocarem mais oferta, onde a recompensa por busca deste personagem vai ficando cada vez mais alta (se acumulando)....
- o dinheiro esta saindo da conta do banco ou da bag, primeiro ele veja se tem no banco se tiver ja pega de la o valor, senão checa a BP.
o que não esta funcionando e não estou conseguindo finalizar...
- a pessoa que mata o personagem (char) não esta recebendo a recompensa e retirando o personagem morto da lista de hunted....
Agradeço muito quem puder ajudar ou a resolver este problema, ou me fornecer algo ja pronto funcional, para versão 13x.
Att.