LS Arcade

FiveM Resource (opens in a new tab) that allows players to host various arcade lobbies, including team deathmatch, free for all deathmatch and gun game.

Dependencies

Optional Dependencies

Installation

Configure your config

Configure qb-ambulancejob

Here you will need to edit it slightly to ensure the regular death functions don't run when the players in an arena.

If you are using qb-ambulancejob you will need to navigate qb-ambulancejob/client/dead.lua

If you are using another resource to handle player death, you can use it as an example to ensure the arcade works properly.

We're editing gameEventTriggered and adding a check to see if the player is in an arena, and skipping the usualy QB death functions.

AddEventHandler('gameEventTriggered', function(event, data)
    if event == "CEventNetworkEntityDamage" then
        local victim, attacker, victimDied, weapon = data[1], data[2], data[4], data[7]
        if not IsEntityAPed(victim) then return end
        if victimDied and NetworkGetPlayerIndexFromPed(victim) == PlayerId() and IsEntityDead(PlayerPedId()) then
            if not exports['ls-arcade']:isPlayerInArena() then -- HERE
                if not InLaststand then
                    SetLaststand(true)
                elseif InLaststand and not isDead then
                    SetLaststand(false)
                    local playerid = NetworkGetPlayerIndexFromPed(victim)
                    local playerName = GetPlayerName(playerid) .. " " .. "("..GetPlayerServerId(playerid)..")" or Lang:t('info.self_death')
                    local killerId = NetworkGetPlayerIndexFromPed(attacker)
                    local killerName = GetPlayerName(killerId) .. " " .. "("..GetPlayerServerId(killerId)..")" or Lang:t('info.self_death')
                    local weaponLabel = (QBCore.Shared.Weapons and QBCore.Shared.Weapons[weapon] and QBCore.Shared.Weapons[weapon].label) or 'Unknown'
                    local weaponName = (QBCore.Shared.Weapons and QBCore.Shared.Weapons[weapon] and QBCore.Shared.Weapons[weapon].name) or 'Unknown'
                    TriggerServerEvent("qb-log:server:CreateLog", "death", Lang:t('logs.death_log_title', {playername = playerName, playerid = GetPlayerServerId(playerid)}), "red", Lang:t('logs.death_log_message', {killername = killerName, playername = playerName, weaponlabel = weaponLabel, weaponname = weaponName}))
                    deathTime = Config.DeathTime
                    OnDeath()
                    DeathTimer()
                end
            else -- HERE
                isDead = true
                local killerId = NetworkGetPlayerIndexFromPed(attacker)
                TriggerServerEvent('ls-arcade:server:playerKilled', GetPlayerServerId(killerId))
            end -- HERE
        end
    end
end)

Still in the same file, find the function called DrawTxt and edit as follows.

We're adding another check if the player is in an arena, and skipping the DrawTxt() function.

local function DrawTxt(x, y, width, height, scale, text, r, g, b, a, _)
    if exports['ls-arcade']:isPlayerInArena() then return end -- HERE
    SetTextFont(4)
    SetTextProportional(0)
    SetTextScale(scale, scale)
    SetTextColour(r, g, b, a)
    SetTextDropShadow(0, 0, 0, 0,255)
    SetTextEdge(2, 0, 0, 0, 255)
    SetTextDropShadow()
    SetTextOutline()
    SetTextEntry("STRING")
    AddTextComponentString(text)
    DrawText(x - width/2, y - height/2 + 0.005)
end

Next we're gonna register a new net event and place it inside the qb-ambulancejob, it doesn't matter where you put it, you can place it anywhere inside qb-ambulancejob/client/dead.lua.

RegisterNetEvent('ls-arcade:client:revivePlayer', function(coords)
    isDead = false
    local ped = PlayerPedId()
 
    NetworkResurrectLocalPlayer(coords.x, coords.y, coords.z, GetEntityHeading(ped), true, false)
    SetEntityInvincible(ped, true)
    SetEntityAlpha(ped, 140)
 
    TriggerEvent('ls-arcade:client:clearBleeding')
 
    CreateThread(function()
        Wait(1000)
        while true do
            local vel = GetEntityVelocity(ped)
            if vel.x ~= 0 then
                SetEntityInvincible(ped, false)
                SetEntityAlpha(ped, 255)
                return
            end
            DisablePlayerFiring(PlayerId(), true) -- Disable weapon firing
            Wait(0)
        end
    end)
end)

Next we're gonna head over to qb-ambulancejob/client/main.lua and register another net event at the bottom of the file.

This event is used so that any bleed damage a player has sustained will be reset up on respawning.

RegisterNetEvent('ls-arcade:client:clearBleeding', function()
    isBleeding = 0
    bleedTickTimer = 0
    advanceBleedTimer = 0
    fadeOutTimer = 0
    blackoutTimer = 0
    onDrugs = 0
    wasOnDrugs = false
    onPainKiller = 0
    wasOnPainKillers = false
    injured = {}
 
    for k, v in pairs(BodyParts) do
        v.isDamaged = false
        v.severity = 0
    end
 
    TriggerServerEvent('hospital:server:SyncInjuries', {
        limbs = BodyParts,
        isBleeding = tonumber(isBleeding)
    })
 
    CurrentDamageList = {}
    TriggerServerEvent('hospital:server:SetWeaponDamage', CurrentDamageList)
 
    ProcessRunStuff(PlayerPedId())
 
    TriggerServerEvent('hospital:server:SyncInjuries', {
        limbs = BodyParts,
        isBleeding = tonumber(isBleeding)
    })
end)
 

Optional: Configure ox_inventory

If you are using ox_inventory you need to add some logic so that you are able to be given weapons in the arena.

navigate to ox_inventory/client.lua

Inside the ox_inventory:setPlayerInventory event, edit as follows.

Towards the bottom of the event, you'll find a function that looks like this:

client.interval = SetInterval(function()
 
end)

Replace that function with the one below. Don't worry, we're not editing any of overextended's logic, just adding our own.

client.interval = SetInterval(function()
    if invOpen == false then
        playerCoords = GetEntityCoords(playerPed)
 
        if currentWeapon and IsPedUsingActionMode(playerPed) then
            SetPedUsingActionMode(playerPed, false, -1, 'DEFAULT_ACTION')
        end
 
    elseif invOpen == true then
        if not canOpenInventory() then
            client.closeInventory()
        else
            playerCoords = GetEntityCoords(playerPed)
 
            if currentInventory and not currentInventory.ignoreSecurityChecks then
                if currentInventory.type == 'otherplayer' then
                    local id = GetPlayerFromServerId(currentInventory.id)
                    local ped = GetPlayerPed(id)
                    local pedCoords = GetEntityCoords(ped)
 
                    if not id or #(playerCoords - pedCoords) > 1.8 or not (client.hasGroup(shared.police) or canOpenTarget(ped)) then
                        client.closeInventory()
                        lib.notify({ id = 'inventory_lost_access', type = 'error', description = locale('inventory_lost_access') })
                    else
                        TaskTurnPedToFaceCoord(playerPed, pedCoords.x, pedCoords.y, pedCoords.z, 50)
                    end
 
                elseif currentInventory.coords and (#(playerCoords - currentInventory.coords) > (currentInventory.distance or 2.0) or canOpenTarget(playerPed)) then
                    client.closeInventory()
                    lib.notify({ id = 'inventory_lost_access', type = 'error', description = locale('inventory_lost_access') })
                end
            end
        end
    end
 
    if client.parachute and GetPedParachuteState(playerPed) ~= -1 then
        Utils.DeleteEntity(client.parachute)
        client.parachute = false
    end
 
    if EnableWeaponWheel then return end
 
    local weaponHash = GetSelectedPedWeapon(playerPed)
 
    if exports['ls-arcade']:isPlayerInArena() then goto skipWeaponCheck end --HERE
 
    if currentWeapon then
        if weaponHash ~= currentWeapon.hash and currentWeapon.timer then
            local weaponCount = Items[currentWeapon.name]?.count
 
            if weaponCount > 0 then
                SetCurrentPedWeapon(playerPed, currentWeapon.hash, true)
                SetAmmoInClip(playerPed, currentWeapon.hash, currentWeapon.metadata.ammo)
                SetPedCurrentWeaponVisible(playerPed, true, false, false, false)
 
                weaponHash = GetSelectedPedWeapon(playerPed)
            end
 
            if weaponHash ~= currentWeapon.hash then
                currentWeapon = Weapon.Disarm(currentWeapon, true)
            end
        end
    elseif client.weaponmismatch and not client.ignoreweapons[weaponHash] then
 
        local weaponType = GetWeapontypeGroup(weaponHash)
 
        if weaponType ~= 0 and weaponType ~= `GROUP_UNARMED` then
 
            Weapon.Disarm(currentWeapon, true)
        end
    end
 
    ::skipWeaponCheck:: -- HERE
end, 200)

Optional: Configure qb-smallresources

If you are using qb-inventory you can add some logic to skip any weapon draw animations while in the arcade.

Navigate to qb-smallresources/client/weapdraw.lua and find the net event called weapons:client:DrawWeapon and replace it with the code below.

Keep in mind, this is version 1.3.1, older or newer version may look different.

RegisterNetEvent('weapons:client:DrawWeapon', function()
    if GetResourceState('qb-inventory') == 'missing' then return end -- This part is only made to work with qb-inventory, other inventories might conflict
    local sleep
    local weaponcheck = 0
    while true do
        if exports['ls-arcade']:isPlayerInArena() then goto skip end -- HERE
        local ped = PlayerPedId()
        sleep = 250
        if DoesEntityExist(ped) and not IsEntityDead(ped) and not IsPedInParachuteFreeFall(ped) and not IsPedFalling(ped) and (GetPedParachuteState(ped) == -1 or GetPedParachuteState(ped) == 0) then
            sleep = 0
            if currWeapon ~= GetSelectedPedWeapon(ped) then
                local pos = GetEntityCoords(ped, true)
                local rot = GetEntityHeading(ped)
 
                local newWeap = GetSelectedPedWeapon(ped)
                SetCurrentPedWeapon(ped, currWeapon, true)
                loadAnimDict("reaction@intimidation@1h")
                loadAnimDict("reaction@intimidation@cop@unarmed")
                loadAnimDict("rcmjosh4")
                loadAnimDict("weapons@pistol@")
 
                local HolsterVariant = GetPedDrawableVariation(ped, 8)
                WearingHolster = false
                for i = 1,#Config.HolsterVariant,1 do
                    if HolsterVariant == Config.HolsterVariant[i] then
                        WearingHolster = true
                    end
                end
                if CheckWeapon(newWeap) then
                    if holstered then
                        if WearingHolster then
                            --TaskPlayAnim(ped, "rcmjosh4", "josh_leadout_cop2", 8.0, 2.0, -1, 48, 10, 0, 0, 0 )
                            canFire = false
                            CeaseFire()
                            currentHolster = GetPedDrawableVariation(ped, 7)
                            currentHolsterTexture = GetPedTextureVariation(ped, 7)
                            TaskPlayAnimAdvanced(ped, "rcmjosh4", "josh_leadout_cop2", pos.x, pos.y, pos.z, 0, 0, rot, 3.0, 3.0, -1, 50, 0, 0, 0)
                            Wait(300)
                            SetCurrentPedWeapon(ped, newWeap, true)
 
                            if IsWeaponHolsterable(newWeap) then
                                SetPedComponentVariation(ped, 7, currentHolster == 8 and 2 or currentHolster == 1 and 3 or currentHolster == 6 and 5, currentHolsterTexture, 2)
                            end
                            currWeapon = newWeap
                            Wait(300)
                            ClearPedTasks(ped)
                            holstered = false
                            canFire = true
                        else
                            canFire = false
                            CeaseFire()
                            TaskPlayAnimAdvanced(ped, "reaction@intimidation@1h", "intro", pos.x, pos.y, pos.z, 0, 0, rot, 8.0, 3.0, -1, 50, 0, 0, 0)
                            Wait(1000)
                            SetCurrentPedWeapon(ped, newWeap, true)
                            currWeapon = newWeap
                            Wait(1400)
                            ClearPedTasks(ped)
                            holstered = false
                            canFire = true
                        end
                    elseif newWeap ~= currWeapon and CheckWeapon(currWeapon) then
                        if WearingHolster then
                            canFire = false
                            CeaseFire()
 
                            TaskPlayAnimAdvanced(ped, "reaction@intimidation@cop@unarmed", "intro", pos.x, pos.y, pos.z, 0, 0, rot, 3.0, 3.0, -1, 50, 0, 0, 0)
                            Wait(500)
 
                            if IsWeaponHolsterable(currWeapon) then
                                SetPedComponentVariation(ped, 7, currentHolster, currentHolsterTexture, 2)
                            end
 
                            SetCurrentPedWeapon(ped, `WEAPON_UNARMED`, true)
                            currentHolster = GetPedDrawableVariation(ped, 7)
                            currentHolsterTexture = GetPedTextureVariation(ped, 7)
 
                            TaskPlayAnimAdvanced(ped, "rcmjosh4", "josh_leadout_cop2", pos.x, pos.y, pos.z, 0, 0, rot, 3.0, 3.0, -1, 50, 0, 0, 0)
                            Wait(300)
                            SetCurrentPedWeapon(ped, newWeap, true)
 
                            if IsWeaponHolsterable(newWeap) then
                                SetPedComponentVariation(ped, 7, currentHolster == 8 and 2 or currentHolster == 1 and 3 or currentHolster == 6 and 5, currentHolsterTexture, 2)
                            end
 
                            Wait(500)
                            currWeapon = newWeap
                            ClearPedTasks(ped)
                            holstered = false
                            canFire = true
                        else
                            canFire = false
                            CeaseFire()
                            TaskPlayAnimAdvanced(ped, "reaction@intimidation@1h", "outro", pos.x, pos.y, pos.z, 0, 0, rot, 8.0, 3.0, -1, 50, 0, 0, 0)
                            Wait(1600)
                            SetCurrentPedWeapon(ped, `WEAPON_UNARMED`, true)
                            TaskPlayAnimAdvanced(ped, "reaction@intimidation@1h", "intro", pos.x, pos.y, pos.z, 0, 0, rot, 8.0, 3.0, -1, 50, 0, 0, 0)
                            Wait(1000)
                            SetCurrentPedWeapon(ped, newWeap, true)
                            currWeapon = newWeap
                            Wait(1400)
                            ClearPedTasks(ped)
                            holstered = false
                            canFire = true
                        end
                    else
                        if WearingHolster then
                            SetCurrentPedWeapon(ped, `WEAPON_UNARMED`, true)
                            currentHolster = GetPedDrawableVariation(ped, 7)
                            currentHolsterTexture = GetPedTextureVariation(ped, 7)
                            TaskPlayAnimAdvanced(ped, "rcmjosh4", "josh_leadout_cop2", pos.x, pos.y, pos.z, 0, 0, rot, 3.0, 3.0, -1, 50, 0, 0, 0)
                            Wait(300)
                            SetCurrentPedWeapon(ped, newWeap, true)
 
                            if IsWeaponHolsterable(newWeap) then
                                SetPedComponentVariation(ped, 7, currentHolster == 8 and 2 or currentHolster == 1 and 3 or currentHolster == 6 and 5, currentHolsterTexture, 2)
                            end
 
                            currWeapon = newWeap
                            Wait(300)
                            ClearPedTasks(ped)
                            holstered = false
                            canFire = true
                        else
                            SetCurrentPedWeapon(ped, `WEAPON_UNARMED`, true)
                            TaskPlayAnimAdvanced(ped, "reaction@intimidation@1h", "intro", pos.x, pos.y, pos.z, 0, 0, rot, 8.0, 3.0, -1, 50, 0, 0, 0)
                            Wait(1000)
                            SetCurrentPedWeapon(ped, newWeap, true)
                            currWeapon = newWeap
                            Wait(1400)
                            ClearPedTasks(ped)
                            holstered = false
                            canFire = true
                        end
                    end
                else
                    if not holstered and CheckWeapon(currWeapon) then
                        if WearingHolster then
                            canFire = false
                            CeaseFire()
                            TaskPlayAnimAdvanced(ped, "reaction@intimidation@cop@unarmed", "intro", pos.x, pos.y, pos.z, 0, 0, rot, 3.0, 3.0, -1, 50, 0, 0, 0)
                            Wait(500)
 
                            if IsWeaponHolsterable(currWeapon) then
                                SetPedComponentVariation(ped, 7, currentHolster, currentHolsterTexture, 2)
                            end
 
                            SetCurrentPedWeapon(ped, `WEAPON_UNARMED`, true)
                            ClearPedTasks(ped)
                            SetCurrentPedWeapon(ped, newWeap, true)
                            holstered = true
                            canFire = true
                            currWeapon = newWeap
                        else
                            canFire = false
                            CeaseFire()
                            TaskPlayAnimAdvanced(ped, "reaction@intimidation@1h", "outro", pos.x, pos.y, pos.z, 0, 0, rot, 8.0, 3.0, -1, 50, 0, 0, 0)
                            Wait(1400)
                            SetCurrentPedWeapon(ped, `WEAPON_UNARMED`, true)
                            ClearPedTasks(ped)
                            SetCurrentPedWeapon(ped, newWeap, true)
                            holstered = true
                            canFire = true
                            currWeapon = newWeap
                        end
                    else
                        SetCurrentPedWeapon(ped, newWeap, true)
                        holstered = false
                        canFire = true
                        currWeapon = newWeap
                    end
                end
            end
        end
        Wait(sleep)
        if currWeapon == nil or currWeapon == `WEAPON_UNARMED` then
            weaponcheck = weaponcheck + 1
            if weaponcheck == 2 then
                break
            end
        end
        ::skip::
    end
end)
 

Optional: Configure Emergency Dispatch

It's recommended to configure whatever dispatch resource you may use, so that certain calls will be ignored while the player is in the arcade.

Use the isPlayerInArena export to disable certain calls from being triggered

Finished

If you have any issues at all with setting up the script, or run into any bugs, please do hesitate to join our discord (opens in a new tab) and create a ticket.