Browse docs

External Death Screen

Replace the bundled death-screen UI while keeping Sky Ambulancejob death state, timers, dispatch, AI Medic, respawn, and revive handling authoritative.

Overview

External mode disables only the bundled death-screen NUI and its focus handling. Sky Ambulancejob continues to own the death state, persistence, bleed-out timer, dispatch requests, AI Medic requests, respawn rules, reconnect handling, death causes, injuries, and revives.

An external death-screen resource is responsible for presentation and user input. It should read the published state and request supported actions instead of creating a second death system.

Job Configurator Setup

Use the following path:

/jobconfigAmbulance JobsSettingsDeath ScreenGeneralIntegrationScreen ModeExternalSave

Changes saved through the Job Configurator apply live. A resource restart is not required.

Death Handling is a separate setting. Static uses the configured death animation, while Natural preserves ragdoll physics until the body settles. Changing Death Handling does not enable an external death screen.
  1. Call getDeathState() when the external resource starts.
  2. Listen to sky_ambulancejob:deathStateChanged for complete state snapshots.
  3. Replace the external UI state whenever a new snapshot arrives.
  4. Use requestDeathAction() for dispatch, respawn, and AI Medic actions.
  5. Hide the external UI when state.dead becomes false.

Do not maintain a second authoritative timer or death state. Use remainingSeconds for display and the availability fields to enable or disable actions.

Client Death State

getDeathState()

Returns a complete snapshot for the local player. The export is registered in both internal and external screen modes.

client.lua
local state = exports["sky_ambulancejob"]:getDeathState()

Example snapshot:

{
    dead = true,
    phase = "downed",
    screenMode = "external",
    handlingMode = "natural",
    bodyStable = true,
    deathTimestamp = 1786788000,
    remainingSeconds = 420,

    canRespawn = false,
    respawnBlockedReason = "timer_active",

    canRequestDispatch = true,

    canRequestAiMedic = false,
    aiMedicBlockedReason = "timer_active",
    aiMedicState = "idle",
    aiMedicReason = nil,

    cause = {
        category = "vehicle",
        weaponHash = 0,
        attackerServerId = nil
    }
}

Death State Fields

FieldTypeDescription
deadbooleanWhether the player is currently considered dead by Sky Ambulancejob.
phasestringCurrent death lifecycle phase: alive, settling, downed, treatment, or respawning.
screenModestringConfigured screen mode: internal or external.
handlingModestringConfigured body handling mode: static or natural.
bodyStablebooleanWhether the body has reached a stable position. This is especially relevant in natural handling mode.
deathTimestampnumber | nilUnix timestamp in seconds at which the current death started. It is nil when no death timestamp is available.
remainingSecondsnumberRemaining seconds on the authoritative bleed-out timer. Display this value instead of maintaining another timer.
canRespawnbooleanWhether the player may currently request an early respawn.
respawnBlockedReasonstring | nilMachine-readable reason why respawning is unavailable. It is nil when no restriction applies.
canRequestDispatchbooleanWhether the player may currently send a dispatch request.
canRequestAiMedicbooleanWhether the player may currently request an AI Medic.
aiMedicBlockedReasonstring | nilMachine-readable reason why the AI Medic cannot currently be requested.
aiMedicStatestringCurrent AI Medic lifecycle state.
aiMedicReasonstring | nilAdditional reason associated with the current AI Medic state, such as a failure or cancellation reason.
causetable | nilDetected death-cause information. It is nil when no cause information is available.

Death Phases

PhaseDescription
aliveNo active death state exists.
settlingThe player died in natural handling mode and the body is still moving.
downedThe death state is active and normal death-system interactions are available.
treatmentA medic is currently treating the player.
respawningA respawn request was accepted and is currently being processed.

Respawn Blocked Reasons

CodeDescription
player_not_deadThe player is not currently dead.
respawn_in_progressA respawn is already being processed.
knockout_activeEarly respawn is unavailable during a knockout.
early_respawn_disabledEarly respawn is disabled in the configuration.
timer_activeThe configured waiting period has not elapsed.
medics_onlineRespawn is blocked because medics are online.
self_respawn_blockedSelf-respawn is blocked for the current death.

AI Medic State

The standard AI Medic lifecycle uses these states:

StateDescription
idleNo AI Medic request is active.
requestingA request is being validated.
dispatchedAn AI Medic was dispatched.
drivingThe AI Medic is travelling to the player.
arrivedThe AI Medic reached the player.
revivingThe AI Medic is performing the revive.
finishedThe AI Medic mission completed.
failedThe request or mission failed. Read aiMedicReason for additional context.
cooldownAnother request is temporarily blocked by a cooldown.

AI Medic Blocked Reasons

CodeDescription
player_not_deadThe player is not currently dead.
respawn_in_progressA respawn is already being processed.
knockout_activeAI Medic requests are unavailable during a knockout.
ai_medic_disabledThe AI Medic feature is disabled.
body_not_stableThe body is still moving in natural handling mode.
revive_blockedThe current death state prevents an AI Medic revive.
medics_onlineThe AI Medic is unavailable because human medics are online.
already_activeAn AI Medic request is already active.
timer_activeThe configured waiting period has not elapsed.

Death Cause

When available, state.cause contains:

{
    category = "vehicle",
    weaponHash = 0,
    attackerServerId = nil
}
FieldTypeDescription
categorystring | nilNormalized detected death category.
weaponHashnumber | nilFiveM weapon or damage-source hash associated with the death.
attackerServerIdnumber | nilServer ID of the detected attacker, or nil when no player attacker was identified.

Pending AI Medic Offer

When a remote AI Medic offer is waiting for the player, the client snapshot additionally contains:

state.aiMedicOffer = {
    pending = true,
    dispatcherName = "Alex",
    remainingSeconds = 25
}

The object is omitted when no offer is pending.

Death State Event

sky_ambulancejob:deathStateChanged

This local client event publishes the same complete snapshot as getDeathState(). Use it for UI updates instead of polling every frame.

client.lua
AddEventHandler("sky_ambulancejob:deathStateChanged", function(state)
    if not state.dead then
        -- Hide the external death screen.
        return
    end

    -- Show or update the external death screen.
    -- Display state.remainingSeconds.
    -- Use the canRequest* fields to control action buttons.
end)

Call getDeathState() once during resource startup because an external resource can start after the current death began and therefore may not have seen the first event.

Requesting Death Actions

requestDeathAction(action, payload?)

Requests an action for the local player. Sky Ambulancejob validates the current death state, timers, prices, medic availability, cooldowns, and all other restrictions.

client.lua
local success, result = exports["sky_ambulancejob"]:requestDeathAction(action, payload)

Supported actions:

ActionPurposePayload
request_dispatchSend the configured death dispatch.None
request_early_respawnRequest the configured early respawn.Optional { hospitalId = "pillbox" }
request_ai_medicRequest the configured AI Medic.None
respond_ai_medic_offerAccept or reject a pending remote AI Medic offer.Required { accepted = true } or { accepted = false }

Request a Dispatch

client.lua
local success, result = exports["sky_ambulancejob"]:requestDeathAction("request_dispatch")

Request an Early Respawn

client.lua
local success, result = exports["sky_ambulancejob"]:requestDeathAction("request_early_respawn", {
    hospitalId = "pillbox" -- Optional configured hospital ID
})

Request an AI Medic

client.lua
local success, result = exports["sky_ambulancejob"]:requestDeathAction("request_ai_medic")

Respond to an AI Medic Offer

client.lua
local success, result = exports["sky_ambulancejob"]:requestDeathAction("respond_ai_medic_offer", {
    accepted = true
})

Set accepted to false to reject the offer.

Action Results

A successful request returns:

true, {
    action = "request_dispatch"
}

A rejected request returns:

false, {
    code = "timer_active",
    message = "The configured waiting time has not elapsed."
}

The code is the machine-readable value intended for program logic. The English message is a developer diagnostic. External UIs should map the code to their own localized user-facing message.

Possible action error codes include:

invalid_action
invalid_payload
player_not_dead
respawn_in_progress
knockout_active
dispatch_disabled
dispatch_already_sent
early_respawn_disabled
timer_active
medics_online
self_respawn_blocked
ai_medic_disabled
body_not_stable
revive_blocked
already_active
on_cooldown
cooldown_active
no_pending_offer
request_blocked_by_hook
request_failed
payment_failed
not_enough_money
disabled
not_dead
remote_wait
target_offline

Simple Client Death Check

Use isDead() when only a boolean is required:

client.lua
local dead = exports["sky_ambulancejob"]:isDead()

For an external death screen, getDeathState() is normally preferable because it also provides the timer, phase, action availability, and blocked reasons.

Server API

getDeathState(playerId)

Returns the server-authoritative death snapshot for a player. It returns nil for an invalid or offline player.

server.lua
local state = exports["sky_ambulancejob"]:getDeathState(playerId)

if not state then
    -- Invalid player ID or the player is offline.
    return
end

isDead(playerId)

Use this export when only a server-side boolean is required:

server.lua
local dead = exports["sky_ambulancejob"]:isDead(playerId)

revive(playerId, reason?)

Revives a player through the normal server-authoritative cleanup and logging path:

server.lua
local success = exports["sky_ambulancejob"]:revive(
    playerId,
    "external_deathscreen"
)

The reason may also be supplied as a table:

server.lua
local success = exports["sky_ambulancejob"]:revive(playerId, {
    reason = "external_deathscreen"
})
revive is intended only for trusted server resources. Never expose an unrestricted client event that forwards a client-provided player ID to this export.

Internal UI Exports

These client exports belong to the bundled internal death-screen UI:

client.lua
exports["sky_ambulancejob"]:open()
exports["sky_ambulancejob"]:updateTime(seconds)
exports["sky_ambulancejob"]:addTime(seconds)

They must not be used by an external death-screen integration. In external mode they return:

false, {
    code = "external_deathscreen_active",
    message = "The bundled deathscreen UI is disabled because external mode is active."
}

Read the timer through getDeathState() and request gameplay actions through requestDeathAction().

Authority and Security

The external death screen must not:

  • set the player death state itself;
  • maintain a separate authoritative bleed-out timer;
  • revive the local player directly from client code;
  • trigger undocumented internal server events;
  • trust a client-provided player ID; or
  • bypass requestDeathAction() validation.

Sky Ambulancejob remains authoritative for death state, persistence, respawn, payments, dispatch, AI Medic availability, and revive handling.

Support

When opening an integration support request, include the Sky Ambulancejob version, whether the integration runs on the client or server, the requested action, and the returned error code.

Join Discord