handcuffsPrison Escape

Prompt Prison Escape


chevron-rightOverviewhashtag

This resource adds an immersive toilet-based escape minigame for prison cells.

Players must unscrew 4 screws from a toilet tank cover to reveal an escape route. The system includes:

  • Custom enter / work / exit animation sequences

  • Cursor-based screw removal minigame (hold LMB to progress)

  • Persistent progress (unscrewed screws stay unscrewed if player leaves)

  • Multiple interaction systems (ox_target, qb-target, or TextUI)

  • Optional inventory requirements (ox_inventory, qb-inventory)


Installation Instructions

1

Step 1 โ€” Install dependencies

This resource requires:

  • ox_lib (required)

Optional (recommended depending on your server):

  • ox_target or qb-target

  • ox_inventory or qb-inventory (only if you want required items)

2

Step 2 โ€” Add the resource

Place the folder inside your resources directory:

resources/prompt_prison_escape
3

Step 3 โ€” Start order (server.cfg)

Add to your server.cfg:

ensure ox_lib
ensure prompt_prison_escape

If you use a target system, ensure it is started before this resource.

4

Step 4 โ€” Integrate with your jail system (required)

Open:

config/config_s.lua

Replace the function:

-- โš ๏ธ CRITICAL INTEGRATION POINT โš ๏ธ
-- Return TRUE to allow, FALSE to deny
isPlayerInPrion = function(source)
    return true
end

with your jail/prison check (examples in the Additional Information section).

5

Step 5 โ€” Restart & test

Restart your server. Go to a prison cell area that uses the supported toilet models and confirm the interaction appears.

If the player can start the minigame and screw progress saves correctly, installation was successful โœ…

Join Discordarrow-up-right


circle-exclamation

chevron-rightAdditional Informationhashtag

Dependencies

Required:

  • ox_lib

Optional (pick what your server uses):

  • Interaction: ox_target or qb-target

  • Item checks: ox_inventory or qb-inventory (only if you enable requiredItem)


Configuration

Client: config/config_c.lua

return {
    -- Interaction system: 'auto' | 'ox_target' | 'qb-target' | 'textUI' | 'custom'
    interaction = 'auto',

    -- Item required to start (empty string = no requirement)
    -- Works with ox_inventory or qb-inventory
    requiredItem = '',

    -- UI location for screw selection:
    -- 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
    -- 'middle-left' | 'middle-right' | 'center'
    uiLocation = 'middle-left',

    -- TextUI functions (customize for your framework)
    textUI = {
        hide = function()
            lib.hideTextUI()
        end,
        show = function(text)
            lib.showTextUI(text)
        end,
    },

    toilet = {
        -- Screw positions (do not modify unless you know what you're doing)
        screwOffsets = { ... },

        screwModel = joaat('prompt_prison_screw'),
        screwDriverModel = joaat('v_ind_cs_screwdrivr3'),

        -- Set true if you are NOT using entity lockdown / need networked objects
        useNetworkedObjects = false
    }
}

THIS I WHERE YOU WOULD WANT TO START YOUR INTEGRATION INTO OTHER SCRIPTS OR FRAMEWORKS down

Server: config/config_s.lua

return {
    debug = true,  -- enable server logs

    -- CRITICAL INTEGRATION POINT
    -- Return true to allow, false to deny
    --
    -- NOTE: the function name is spelled "isPlayerInPrion" in this config.
    isPlayerInPrion = function(source)
        return true
    end
}

Jail Integration Examples

Generic framework (ESX/QBCore/Custom job check)

return {
    debug = false,

    isPlayerInPrion = function(source)
        local Player = YourFramework.GetPlayer(source)
        if not Player then return false end

        local job = Player.job.name
        return job == 'prisoner' or job == 'inmate'
    end
}

qb-prison style (metadata injail)

return {
    debug = false,

    isPlayerInPrion = function(source)
        local Player = QBCore.Functions.GetPlayer(source)
        if not Player then return false end

        local jailTime = Player.PlayerData.metadata['injail']
        return jailTime and jailTime > 0
    end
}

ESX jail style (jailTime value)

return {
    debug = false,

    isPlayerInPrion = function(source)
        local xPlayer = ESX.GetPlayerFromId(source)
        if not xPlayer then return false end

        local jailTime = xPlayer.get('jailTime') or 0
        return jailTime > 0
    end
}

ND_Jail style (export check)

return {
    debug = false,

    isPlayerInPrion = function(source)
        return exports['ND_Jail']:isPlayerJailed(source)
    end
}

Custom DB check (example concept)

return {
    debug = false,

    isPlayerInPrion = function(source)
        local identifier = GetPlayerIdentifier(source, 0)
        local result = MySQL.Sync.fetchScalar(
            'SELECT jail_time FROM players WHERE identifier = ?',
            { identifier }
        )
        return result and result > 0
    end
}

Callbacks & Events (Reference)

Server callbacks (lib.callback) used by the resource:

  • prompt_prison_escape:createToiletObject

  • prompt_prison_escape:unscrewProgress

  • prompt_prison_escape:getUnscrewedState

  • prompt_prison_escape:completeEscape

  • prompt_prison_escape:stopSitting

Client event used by the resource:

  • prompt_prison_escape:toggleToiletVisibility


Customization

Require an item (optional)

-- config/config_c.lua
requiredItem = 'screwdriver'

Force a specific interaction system (optional)

-- config/config_c.lua
interaction = 'ox_target'   -- or 'qb-target' or 'textUI'

Custom TextUI (optional)

-- config/config_c.lua
textUI = {
    hide = function()
        exports['your_ui']:HideTextUI()
    end,
    show = function(text)
        exports['your_ui']:ShowTextUI(text)
    end,
},

Custom interaction mode (optional) Implement inside client/editable/interaction.lua (custom mode must call onUse(entity) when interacted).

-- example concept
exports['your_interact_system']:AddInteraction({
    model = toiletHash,
    label = locale('interaction_label'),
    action = function(entity)
        onUse(entity)
    end
})

Troubleshooting

Interaction not showing

  • Set interaction explicitly instead of auto

  • Confirm the prison uses supported toilet models in the cell area

  • Confirm your isPlayerInPrion(source) returns true for jailed players

Minigame starts but progress doesnโ€™t save

  • Ensure ox_lib is running

  • Check server console for callback errors

  • Confirm the resource isnโ€™t restarting/crashing

Players can use it when they shouldnโ€™t

  • Your isPlayerInPrion(source) check is returning true incorrectly

  • Add real jail-time / jailed-state validation from your prison script


File Structure (Reference)

prompt_prison_escape/
โ”œโ”€โ”€ client/
โ”‚   โ”œโ”€โ”€ main.lua
โ”‚   โ”œโ”€โ”€ events.lua
โ”‚   โ”œโ”€โ”€ utils.lua
โ”‚   โ”œโ”€โ”€ editable/
โ”‚   โ”‚   โ””โ”€โ”€ interaction.lua
โ”‚   โ””โ”€โ”€ minigame/
โ”‚       โ”œโ”€โ”€ screw_game.lua
โ”‚       โ”œโ”€โ”€ camera_manager.lua
โ”‚       โ””โ”€โ”€ animation_controller.lua
โ”œโ”€โ”€ config/
โ”‚   โ”œโ”€โ”€ config_c.lua
โ”‚   โ””โ”€โ”€ config_s.lua
โ”œโ”€โ”€ server/
โ”‚   โ””โ”€โ”€ server.lua
โ”œโ”€โ”€ locales/
โ”‚   โ”œโ”€โ”€ en.json
โ”‚   โ”œโ”€โ”€ de.json
โ”‚   โ”œโ”€โ”€ es.json
โ”‚   โ”œโ”€โ”€ fr.json
โ”‚   โ””โ”€โ”€ pl.json
โ”œโ”€โ”€ stream/
โ”‚   โ””โ”€โ”€ *.ycd
โ”œโ”€โ”€ web/
โ”‚   โ””โ”€โ”€ (NUI)
โ””โ”€โ”€ fxmanifest.lua

Note: This resource handles cell escape only. Anything after escape (alerts, recapture, jail time changes, routes) should be handled by your prison system or additional scripts.

Last updated