Bodybag Script

A script by Eviate

No reviews yet.
Bodybag Script main image

Full Description

Bodybag Script

Do you want to bring more immersive roleplay to your server, even after the death of a player? This bodybag script might be the addition you are looking for.

:shopping_cart: Get it here: gamzkystore.com

:question: Support: Discord

:movie_camera: Detailed preview: Youtube

Features

  • Will work on any framework and only requires a target system to interact with dead players.
  • Optional job and/or item requirement before placing a bodybag.
  • Uses statebags for seamless synchronization between clients, the script can even be restarted when in use without causing problems.
  • Bodybags can be removed as well (this feature can also be disabled).
  • Exports and events are available to add or remove bodybags via other scripts, enabling easy integration into your server.
  • Highly configurable, bridge functions also enable you to edit the most important code.

Resmon: 0.00ms

The code snippets below are accessible in the encrypted version:

Config
Config = {}

-- The distance the player has to be to interact with the target
Config.InteractDistance = 2.0

-- A saveguard such that people cannot bodybag a target that is to far away due to desync
Config.MaximumBodybagDistance = 25.0

-- The prop used as a bodybag
Config.BodybagModel = 'xm_prop_body_bag'

-- If the bodybag should be frozen in place
Config.FreezeBodybag = true

-- If the players can also remove the bodybag
Config.CanRemoveBodybag = true

-- The job that is required to put the body in a bodybag, or set Enabled to false to not require a job
Config.RequiredJob = {
    Enabled = true,
    Name = 'police',
}

-- The item that is required to put the body in a bodybag, or set Enabled to false to not require an item
Config.RequiredItem = {
    Enabled = true,
    ItemName = 'bodybag',
    ItemAmount = 1,
}

-- The animations to play when putting a player in a bodybag or removing a bodybag
Config.Animations = {
    ['put_in_bodybag'] = {
        Dict = 'missexile3', -- Replace to '' to not play an animation
        Name = 'ex03_dingy_search_case_base_michael',
        Time = 2000,
        Blend = 8.0,
        Flag = 1,
    },
    ['remove_bodybag'] = {
        Dict = 'missexile3', -- Replace to '' to not play an animation
        Name = 'ex03_dingy_search_case_base_michael',
        Time = 2000,
        Blend = 8.0,
        Flag = 1,
    },
}

-- Language configuration
Config.Locales = {
    ['put_in_bodybag'] = 'Put in bodybag',
    ['remove_bodybag'] = 'Remove bodybag',
    ['missing_required_job'] = 'You do not have the required job',
    ['missing_required_item'] = 'You do not have the required item',
}

-- Adds some prints for debugging
Config.Debug = false
Accessible Client Bridge Functions
Functions = {}

-- A function that checks if the player can interact with the target
Functions.CanInteract = function()
    local ped = PlayerPedId()
    local isPedInVehicle = IsPedInAnyVehicle(ped, false)
    local isPedDead = IsPedDeadOrDying(ped, true)

    if (isPedInVehicle or isPedDead) then
        return false
    end

    return true
end

-- A function that checks if the target can be placed in a bodybag, by default returns only true if the target is dead
Functions.CanTargetBePlacedInBodybag = function(entity)
    local isPedDead = IsPedDeadOrDying(entity, true)
    return isPedDead
end

-- This function is triggered after the bodybag is created, you can execute any code you want here
Functions.OnBodybagCreated = function(bodybagEntity)
    local ped = PlayerPedId()
    SetEntityVisible(ped, false, 0)
    SetEntityCollision(ped, false, true)
    FreezeEntityPosition(ped, true)
end

-- This function is triggered after the bodybag is removed, you can execute any code you want here
Functions.OnBodybagRemoved = function()
    local ped = PlayerPedId()
    SetEntityCollision(ped, true, true)
    SetEntityVisible(ped, true, 0)
    FreezeEntityPosition(ped, false)
end

Functions.AddGlobalTargetOptions = function()
    -- For the people ussing ox-target
    if (GetResourceState('ox_target') == 'started') then
        exports.ox_target:addGlobalPlayer({
            {
                icon = 'fas fa-briefcase',
                label = Config.Locales['put_in_bodybag'],
                distance = Config.InteractDistance,
                groups = Config.RequiredJob.Enabled and Config.RequiredJob.Name or nil,
                items = Config.RequiredItem.Enabled and Config.RequiredItem.ItemName or nil,
                onSelect = function(data)
                    AttemptUseBodybag(data.entity)
                end,
                canInteract = function(entity)
                    return (Functions.CanInteract() and IsTargetValid(entity) and Functions.CanTargetBePlacedInBodybag(entity) and not IsTargetEntityInBodybag(entity))
                end
            },
        })
        return
    end

    -- For the people using qb-target
    if (GetResourceState('qb-target') == 'started') then
        exports['qb-target']:AddGlobalPlayer({
            options = {
                {
                    icon = 'fas fa-briefcase',
                    label = Config.Locales['put_in_bodybag'],
                    job = Config.RequiredJob.Enabled and Config.RequiredJob.Name or nil,
                    item = Config.RequiredItem.Enabled and Config.RequiredItem.ItemName or nil,
                    action = function(entity)
                        AttemptUseBodybag(entity)
                    end,
                    canInteract = function(entity)
                        return (Functions.CanInteract() and IsTargetValid(entity) and Functions.CanTargetBePlacedInBodybag(entity) and not IsTargetEntityInBodybag(entity))
                    end,
                },
            },
            distance = Config.InteractDistance,
        })
        return
    end

    print('gs_bodybag: [ERROR] No target interaction defined')
end

Functions.AddRemoveBodybagOption = function(bodybagEntityNetIds)
    -- For the people ussing ox-target
    if (GetResourceState('ox_target') == 'started') then
        exports.ox_target:addEntity(bodybagEntityNetIds, {
            {
                icon = 'fas fa-trash-can-arrow-up',
                label = Config.Locales['remove_bodybag'],
                distance = Config.InteractDistance,
                groups = Config.RequiredJob.Enabled and Config.RequiredJob.Name or nil,
                onSelect = function(data)
                    AttemptRemoveBodybag(data.entity)
                end,
                canInteract = function()
                    return (Config.CanRemoveBodybag and Functions.CanInteract())
                end
            },
        })
        return
    end

    -- For the people ussing qb-target
    if (GetResourceState('qb-target') == 'started') then
        exports['qb-target']:AddTargetEntity(bodybagEntityNetIds, {
            options = {
                {
                    icon = 'fas fa-trash-can-arrow-up',
                    label = Config.Locales['remove_bodybag'],
                    job = Config.RequiredJob.Enabled and Config.RequiredJob.Name or nil,
                    action = function(entity)
                        AttemptRemoveBodybag(entity)
                    end,
                    canInteract = function()
                        return (Config.CanRemoveBodybag and Functions.CanInteract())
                    end,
                },
            },
            distance = Config.InteractDistance,
        })
        return
    end

    print('gs_bodybag: [ERROR] No target interaction defined')
end

Accessible Server Bridge Functions
local ESX = nil
local QBCore = nil

-- Select the correct framework
CreateThread(function()
    if (GetResourceState('es_extended') == 'started') then
        ESX = exports['es_extended']:getSharedObject()
    elseif (GetResourceState('qb-core') == 'started') then
        QBCore = exports['qb-core']:GetCoreObject()
    end
end)

Functions = {}

Functions.CanSourcePlaceTargetInBodybag = function(source, target)
    -- You can add any additional checks here, to prevent abuse if you wish
    return true
end

-- Check if the player has the required job
Functions.DoesPlayerHaveRequiredJob = function(src)
    if (not Config.RequiredJob.Enabled) then
        return true
    end

    -- Case for ESX
    if (ESX ~= nil) then
        local xPlayer = ESX.GetPlayerFromId(src)
        if xPlayer.job.name == Config.RequiredJob.Name then
            return true
        end
        TriggerClientEvent('esx:showNotification', src, Config.Locales['missing_required_job'], 'error')

        -- Case for QBCore
    elseif (QBCore ~= nil) then
        local Player = QBCore.Functions.GetPlayer(src)
        if Player.PlayerData.job.name == Config.RequiredJob.Name then
            return true
        end
        TriggerClientEvent('QBCore:Notify', src, Config.Locales['missing_required_job'], 'error')
    end
    return false
end

-- Check if the player has the required item and remove it
Functions.UseBodybagItem = function(src)
    if (not Config.RequiredItem.Enabled) then
        return true
    end

    -- Case for ESX
    if (ESX ~= nil) then
        local xPlayer = ESX.GetPlayerFromId(src)
        if xPlayer.getInventoryItem(Config.RequiredItem.ItemName).count >= Config.RequiredItem.ItemAmount then
            xPlayer.removeInventoryItem(Config.RequiredItem.ItemName, Config.RequiredItem.ItemAmount)
            return true
        end
        TriggerClientEvent('esx:showNotification', src, Config.Locales['missing_required_item'], 'error')

        -- Case for QBCore
    elseif (QBCore ~= nil) then
        local Player = QBCore.Functions.GetPlayer(src)
        if Player.Functions.GetItemByName(Config.RequiredItem.ItemName).amount >= Config.RequiredItem.ItemAmount then
            Player.Functions.RemoveItem(Config.RequiredItem.ItemName, Config.RequiredItem.ItemAmount)
            return true
        end
        TriggerClientEvent('QBCore:Notify', src, Config.Locales['missing_required_item'], 'error')
    end
    return false
end

Functions.ReturnBodybagItem = function(src)
    if (not Config.RequiredItem.Enabled) then
        return
    end

    -- Case for ESX
    if (ESX ~= nil) then
        local xPlayer = ESX.GetPlayerFromId(src)
        xPlayer.addInventoryItem(Config.RequiredItem.ItemName, Config.RequiredItem.ItemAmount)

        -- Case for QBCore
    elseif (QBCore ~= nil) then
        local Player = QBCore.Functions.GetPlayer(src)
        Player.Functions.AddItem(Config.RequiredItem.ItemName, Config.RequiredItem.ItemAmount)
    end
end

-- The exports below can be triggered from the SERVER which will add or remove a bodybag to/from a specific player (this skips the check for the correct job and/or item)
exports('AddBodybag', AddBodybag)       -- Call through exports.gs_bodybag:AddBodybag(playerServerId)
exports('RemoveBodybag', RemoveBodybag) -- Call through exports.gs_bodybag:RemoveBodybag(playerServerId)

-- The events below can be triggered from the CLIENT which will add or remove a bodybag to/from to the source of the event (this skips the check for the correct job and/or item)
RegisterNetEvent('gs_bodybag:AddBodybagForPlayer', function()
    local src = source
    AddBodybag(src)
end)

RegisterNetEvent('gs_bodybag:RemoveBodybagForPlayer', function()
    local src = source
    RemoveBodybag(src)
end)

Code is accessible No, but there is an unencrypted version
Subscription-based No
Lines (approximately) ~600
Requirements Only a target script (i.e. ox-target or qb-target)
Support Yes