Ir para conteúdo
  • Cadastre-se

Huntpk - Bonty Hunter - sistema de caça por recompensa


Posts Recomendados

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.

 

 

Link para o post
Compartilhar em outros sites

Participe da conversa

Você pode postar agora e se cadastrar mais tarde. Se você tem uma conta, faça o login para postar com sua conta.

Visitante
Responder

×   Você colou conteúdo com formatação.   Remover formatação

  Apenas 75 emojis são permitidos.

×   Seu link foi automaticamente incorporado.   Mostrar como link

×   Seu conteúdo anterior foi restaurado.   Limpar o editor

×   Não é possível colar imagens diretamente. Carregar ou inserir imagens do URL.

  • Quem Está Navegando   0 membros estão online

    Nenhum usuário registrado visualizando esta página.

  • Estatísticas dos Fóruns

    96831
    Tópicos
    519564
    Posts
×
×
  • Criar Novo...

Informação Importante

Confirmação de Termo