# Medical Help

***

<figure><img src="https://3626236831-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fa8uHYewwKFFVyUWKAUtL%2Fuploads%2FTBfoUckDwCnWx9NMrThW%2Fmh.jpg?alt=media&#x26;token=057b6008-7323-4423-8859-d79de06f5c30" alt=""><figcaption></figcaption></figure>

## Overview

XeX MedicalHelp is a premium heal, revive, and carry system for FiveM servers. It provides configurable NPC-based interaction points where players can heal themselves or revive nearby downed players, with EMS count restrictions to ensure medical roleplay is not bypassed when ambulance players are online. A fireman's carry system allows players to transport others. Supports all three major frameworks.

### Supported Frameworks

| Framework  | Version | Status                            |
| ---------- | ------- | --------------------------------- |
| ESX Legacy | 1.6.0+  | ✅ Full Support                    |
| QBCore     | Latest  | ✅ Full Support                    |
| QBox (QBx) | Latest  | ✅ Full Support (requires ox\_lib) |

***

## Features Summary

| Category     | Feature            | Description                                             |
| ------------ | ------------------ | ------------------------------------------------------- |
| **Medical**  | Heal Points        | NPC-based locations where players heal to full HP       |
| **Medical**  | Revive Points      | NPC-based locations to revive downed/dead players       |
| **Medical**  | Medical Animation  | 10-second medic tend animation during revive            |
| **Medical**  | Cost System        | Configurable cash cost per point (or free)              |
| **Carry**    | Fireman's Carry    | Pick up and carry other players                         |
| **Carry**    | Sync System        | Server-synced carry animations between players          |
| **Carry**    | Toggle Command     | Same command to start and stop carrying                 |
| **EMS**      | EMS Restriction    | Points hidden when EMS count exceeds threshold          |
| **EMS**      | Real-time Tracking | Server tracks EMS job changes and connections           |
| **Access**   | Job Whitelisting   | Restrict specific points to certain jobs                |
| **NPC**      | Custom Peds        | Spawn configurable NPC at each point                    |
| **NPC**      | NPC Animation      | Guard idle animation on spawned NPCs                    |
| **NPC**      | Invincible NPCs    | NPCs are frozen, invincible, and non-reactive           |
| **Map**      | Blips              | Per-point configurable map blips (sprite, scale, color) |
| **Map**      | Markers            | Per-point 3D markers with custom type and RGB color     |
| **Interact** | ox\_target         | Optional ox\_target sphere zones or entity targets      |
| **Interact** | Marker + E         | Traditional marker rendering + E key interaction        |
| **Webhook**  | Discord Logging    | Log heal and revive actions with player identifiers     |
| **System**   | Auto Updater       | JSON-based version checker                              |
| **I18n**     | 2 Languages        | English, Spanish                                        |

***

## Installation

### Requirements

* FiveM Server Build 5181+
* Framework: ESX Legacy, QBCore, or QBox
* Optional: [ox\_target](https://github.com/overextended/ox_target) (for target mode)
* Optional: [ox\_lib](https://github.com/overextended/ox_lib) (required for QBox)

### Dependencies by Framework

| Framework | Required                        | Optional   |
| --------- | ------------------------------- | ---------- |
| ESX       | es\_extended, esx\_ambulancejob | ox\_target |
| QBCore    | qb-core                         | ox\_target |
| QBox      | qbx\_core, ox\_lib              | ox\_target |

### Quick Start

{% stepper %}
{% step %}

### Place resource

Place `xex_medicalhelp` in your resources folder.
{% endstep %}

{% step %}

### Enable resource

Add to server.cfg:

```
ensure xex_medicalhelp
```

{% endstep %}

{% step %}

### Configure framework

Set `Config.Framework` to your framework (`'esx'`, `'qb'`, or `'qbx'`).
{% endstep %}

{% step %}

### Configure points

Configure `Config.HRPoints` with your heal/revive locations.
{% endstep %}

{% step %}

### Restart server

Restart server.
{% endstep %}
{% endstepper %}

> Note: If using QBox, ensure `ox_lib` is started before this resource.

***

## Configuration

### General Settings

```lua
Config.Language = 'en'              -- 'en' | 'es'
Config.CheckForUpdates = true       -- Auto version check on start
Config.UseOxTarget = true           -- true = ox_target | false = marker + E key
Config.DrawDistance = 20.0          -- Distance to render markers (marker mode only)
Config.EMSJobName = 'ambulance'     -- Job name used for EMS count tracking
```

| Option                | Default       | Description                                |
| --------------------- | ------------- | ------------------------------------------ |
| `Config.Language`     | `'en'`        | Locale for all text strings                |
| `Config.UseOxTarget`  | `true`        | Use ox\_target zones instead of 3D markers |
| `Config.DrawDistance` | `20.0`        | Distance to start rendering 3D markers     |
| `Config.EMSJobName`   | `'ambulance'` | Job name to track for EMS online count     |

### Framework Settings

```lua
Config.Framework = 'auto'  -- 'auto' | 'esx' | 'qb' | 'qbx'
```

| Value    | Behavior                          |
| -------- | --------------------------------- |
| `'auto'` | Auto-detects: QBox → QBCore → ESX |
| `'esx'`  | Force ESX Legacy                  |
| `'qb'`   | Force QBCore                      |
| `'qbx'`  | Force QBox (requires ox\_lib)     |

### Heal & Revive Points

Each entry in `Config.HRPoints` defines one interaction point:

```lua
Config.HRPoints = {
    {
        pointType = 'revive',           -- 'revive' | 'heal'
        maxEMS = 1,                     -- Hide point when EMS count > this
        cost = 5000,                    -- Cash cost (0 = free)
        location = {                    -- World coordinates
            x = 360.08,
            y = -585.10,
            z = 28.82,
        },
        NPCEnabled = true,             -- Spawn an NPC at this point
        NPCPed = 's_f_y_scrubs_01',    -- Ped model name
        NPCPedPosition = {             -- NPC spawn position + heading
            x = 359.62,
            y = -584.95,
            z = 27.82,
            h = 251.0,
        },
        whitelistedJobs = {},           -- {} = all jobs | {'gang', 'mafia'}
        blip = {
            enabled = true,
            sprite = 51,                -- GTA blip sprite ID
            scale = 0.9,
            color = 1,                  -- GTA blip color ID
        },
        marker = {
            type = 2,                   -- GTA marker type ID
            rgb = { r = 255, g = 0, b = 0 },
        },
    },
    -- ... more points
}
```

| Field             | Type    | Required | Description                              |
| ----------------- | ------- | -------- | ---------------------------------------- |
| `pointType`       | string  | ✅        | `'revive'` or `'heal'`                   |
| `maxEMS`          | number  | ✅        | Max EMS online before point is hidden    |
| `cost`            | number  | ✅        | Cash cost, 0 for free                    |
| `location`        | table   | ✅        | World coordinates `{x, y, z}`            |
| `NPCEnabled`      | boolean | ❌        | Whether to spawn an NPC (default: false) |
| `NPCPed`          | string  | ❌        | Ped model hash name                      |
| `NPCPedPosition`  | table   | ❌        | NPC position `{x, y, z, h}`              |
| `whitelistedJobs` | table   | ❌        | Empty = all jobs allowed                 |
| `blip`            | table   | ❌        | Map blip configuration                   |
| `marker`          | table   | ❌        | 3D marker configuration                  |

### Carry System

```lua
Config.CarryEnabled = true            -- Enable /carry command
Config.CarryCommand = 'carry'         -- Command name
```

### Discord Webhooks

```lua
Config.WebhookEnabled = false
Config.WebhookServerName = 'XeX Server'
Config.Webhook = ''                   -- Discord webhook URL
Config.DateFormat = '%d/%m/%Y [%X]'
Config.IconUrl = 'https://i.imgur.com/EpqKImZ.png'
Config.BotName = 'Auto Medical Bot'
```

***

## How It Works

### Complete Flow

Player approaches medical point → Marker/ox\_target appears (if allowed) → Player interacts (E key or ox\_target):

* Heal: Checks HP < max → charges cost → heals to full → webhook
* Revive: Finds nearest player → checks if dead → charges cost → plays medic animation (10s) → carries (optional) → revives → webhook
* Point hidden if EMS count exceeds maxEMS threshold

### EMS Count Restriction

The server tracks online EMS players in real-time:

* When a player loads with job matching `Config.EMSJobName`, count increments
* When a player changes to/from the EMS job, count updates
* When an EMS player disconnects, count decrements
* Count is broadcast to all clients via `xex_medicalhelp:updateEmsCount`
* Points with `maxEMS < currentEMSCount` are hidden

Use case: When enough real EMS players are online, NPC heal/revive points automatically disappear, encouraging roleplay with real medics.

### Job Whitelisting

Each point can restrict access to specific jobs:

```lua
whitelistedJobs = {}          -- Empty: open to everyone
whitelistedJobs = {'gang'}    -- Only 'gang' job can see/use this point
whitelistedJobs = {'gang', 'mafia'}  -- Multiple jobs allowed
```

This allows creating "illegal" medical points restricted to criminal organizations.

The `isAllowedJobForPoint()` function supports both:

* String job data (ESX format: `myJob = 'police'`)
* Table job data (QB/QBx format: `{name = 'police', grade = 2}`)

### ox\_target vs Marker Mode

| Feature       | ox\_target Mode             | Marker + E Mode                     |
| ------------- | --------------------------- | ----------------------------------- |
| Activation    | `Config.UseOxTarget = true` | `Config.UseOxTarget = false`        |
| Interaction   | Click target icon           | Press E key                         |
| NPC targeting | Entity target on NPC        | Proximity check                     |
| No NPC        | Sphere zone at coords       | Marker at coords                    |
| Performance   | Better (event-based)        | Polling loop (1ms near, 2500ms far) |
| Dependency    | Requires ox\_target         | None                                |

### Revive Mechanics

1. Player interacts with a revive point
2. Finds closest player within 5 units
3. Checks if target player is dead (`health == 0`)
4. If cost > 0, deducts cash via server callback
5. Plays `CODE_HUMAN_MEDIC_TEND_TO_DEAD` scenario (10 seconds)
6. Optionally triggers carry command
7. Triggers revive event:
   * ESX: `esx_ambulancejob:revive`
   * QB: `hospital:client:Revive`
   * QBx: `hospital:client:Revive` (via ox\_lib)

### Heal Mechanics

1. Player interacts with a heal point
2. Checks current HP < max HP
3. If cost > 0, deducts cash via server callback
4. Server triggers client-side heal (`SetEntityHealth` to max)
5. Shows notification

### Carry System Mechanics

The carry system uses a fireman's carry animation:

1. Player executes `/{CarryCommand}` (default: `/carry`)
2. Finds closest player within 5 units
3. First press: attaches target to carrier with carry animation
4. Second press: detaches target and stops animation
5. All carry operations sync through server events

***

## Interaction Modes

### Marker + E Key Mode

When `Config.UseOxTarget = false`:

* 3D markers render at each point within `Config.DrawDistance`
* Help text shows when within 1.5 units
* Press E to interact
* Dynamic wait loop: 1ms near markers, 2500ms when idle

### ox\_target Mode

When `Config.UseOxTarget = true`:

* If NPC is enabled: entity target registered on the NPC ped
* If no NPC: sphere zone at point coordinates (radius 1.5)
* `canInteract` checks: not busy, EMS count, job whitelist
* Icons: `fas fa-heartbeat` (revive), `fas fa-medkit` (heal)

***

## NPC System

Each point can optionally spawn an NPC:

```lua
NPCEnabled = true,
NPCPed = 's_f_y_scrubs_01',
NPCPedPosition = { x = 359.62, y = -584.95, z = 27.82, h = 251.0 },
```

NPCs are configured with:

* Invincible — cannot be killed
* Frozen — cannot be pushed or moved
* Non-reactive — blocks fleeing behavior and temporary events
* Animation — plays `missfbi_s4mop > guard_idle_a` idle animation
* Cleanup — model marked as no longer needed after spawn

***

## Exports & Events

### Server Exports

```lua
-- Trigger manual update check
exports['xex_medicalhelp']:CheckForUpdates()
```

### Server Callbacks

| Callback              | Parameters | Returns   | Description                            |
| --------------------- | ---------- | --------- | -------------------------------------- |
| `xex_revivehelp:paid` | `amount`   | `boolean` | Deduct cash and return success/failure |

### Server Events

| Event                    | Parameters | Description                    |
| ------------------------ | ---------- | ------------------------------ |
| `xex_medicalhelp:heal`   | —          | Heal the triggering player     |
| `xex_medicalhelp:revive` | `targetId` | Revive target player           |
| `xex_medicalhelp:sync`   | carry data | Sync carry animation to target |
| `xex_medicalhelp:stop`   | `targetId` | Stop carry on target           |

### Client Events

| Event                            | Parameters | Description                              |
| -------------------------------- | ---------- | ---------------------------------------- |
| `xex_medicalhelp:updateEmsCount` | `count`    | Update local EMS count                   |
| `xex_medicalhelp:setMyJob`       | `jobName`  | Update local player job                  |
| `xex_medicalhelp:heal`           | —          | Apply heal (set max HP)                  |
| `xex_medicalhelp:syncTarget`     | carry data | Apply carry animation to carried player  |
| `xex_medicalhelp:syncMe`         | carry data | Apply carry animation to carrying player |
| `xex_medicalhelp:cl_stop`        | —          | Stop carry animation and detach          |

### Commands

| Command              | Context        | Description                                            |
| -------------------- | -------------- | ------------------------------------------------------ |
| `/{CarryCommand}`    | Client         | Toggle carrying the nearest player (default: `/carry`) |
| `medicalhelp_update` | Server Console | Manual update check                                    |

***

## Localization

### Supported Languages

| Code | Language |
| ---- | -------- |
| `en` | English  |
| `es` | Español  |

### Locale Keys Reference

| Key                     | English                      | Description                      |
| ----------------------- | ---------------------------- | -------------------------------- |
| `heal_blip_text`        | Heal                         | Map blip label for heal points   |
| `revive_blip_text`      | Revive                       | Map blip label for revive points |
| `press_to_revive`       | Press \[E] to revive injured | Interaction prompt               |
| `press_to_heal`         | Press \[E] to heal wounds.   | Interaction prompt               |
| `heal_in_progress`      | Heal in progress...          | During animation                 |
| `healed`                | You have healed your wounds  | Heal success                     |
| `heal_completed_to`     | %s healed                    | Revive success (with name)       |
| `not_dead_player`       | Player is not dead           | Cannot revive living player      |
| `no_money`              | You don't have enough money  | Insufficient funds               |
| `not_nearby`            | There is no one around       | No player in range               |
| `already_full`          | You are already full health  | Cannot heal at max HP            |
| `webhook_heal_action`   | Heal                         | Webhook embed field              |
| `webhook_heal_title`    | Someone has been healed      | Webhook embed title              |
| `webhook_revive_action` | Has revived %s               | Webhook embed field              |
| `webhook_revive_title`  | Someone has been resurrected | Webhook embed title              |

### Adding Languages

Add a new entry in `locales.lua`:

```lua
Locales['fr'] = {
    ['heal_blip_text'] = 'Soigner',
    ['revive_blip_text'] = 'Réanimer',
    -- ... all keys
}
```

Then set `Config.Language = 'fr'` in `config.lua`.

***

## File Structure

```
xex_medicalhelp/
├── client/
│   ├── esx.lua               # ESX client — heal/revive/carry, markers, ox_target
│   ├── qb.lua                # QBCore client mirror
│   ├── qbx.lua               # QBox client (requires ox_lib)
│   └── utils.lua             # Shared: NPC spawning, job check, heal event
├── server/
│   ├── esx.lua               # ESX server — EMS tracking, payment, webhook
│   ├── qb.lua                # QBCore server mirror
│   ├── qbx.lua               # QBox server (requires ox_lib)
│   └── updater.lua           # Version checker
├── config.lua                # All configuration
├── locales.lua               # Translations (en/es)
├── fxmanifest.lua            # Resource manifest
├── readme.md                 # Quick start readme
└── DOCS.md                   # This documentation
```

***

## Security

| Measure                    | Description                                                    |
| -------------------------- | -------------------------------------------------------------- |
| Server-side payment        | Cash deduction validated on server via callback                |
| EMS count server-tracked   | Count managed entirely server-side, broadcast to clients       |
| Job validation client-side | `isAllowedJobForPoint()` checks job before showing interaction |
| Revive target validation   | Checks closest player exists, is within range, and is dead     |
| isBusy guard               | Prevents spamming interactions while animation plays           |
| Carry distance check       | Carry only works within 5 units of target player               |

***

## Performance

| Aspect          | Detail                                                  |
| --------------- | ------------------------------------------------------- |
| ox\_target mode | Event-based — zero polling when not interacting         |
| Marker mode     | 1ms near markers, 2500ms when idle                      |
| NPC spawn       | Model released after spawn (`SetModelAsNoLongerNeeded`) |
| Carry loop      | 1ms during carry, 1500ms when idle                      |
| EMS updates     | Only on job change/connect/disconnect events            |

***

## Troubleshooting

<details>

<summary>Points not showing</summary>

Check \`maxEMS\` — points hide when enough EMS are online.

</details>

<details>

<summary>Revive not working</summary>

Check \`esx\_ambulancejob\` is running (ESX) or death system is compatible.

</details>

<details>

<summary>ox_target not working</summary>

Verify \`ox\_target\` is started and \`Config.UseOxTarget = true\`.

</details>

<details>

<summary>NPC not spawning</summary>

Check \`NPCEnabled = true\` and ped model name is valid.

</details>

<details>

<summary>Carry not working</summary>

Check \`Config.CarryEnabled = true\` and target is within 5 units.

</details>

<details>

<summary>Job filter not working</summary>

Verify \`whitelistedJobs\` uses exact job names from your framework.

</details>

<details>

<summary>Payment failing</summary>

Check player has enough cash (cost is deducted from cash, not bank).

</details>

<details>

<summary>QBox errors</summary>

Ensure \`ox\_lib\` is started **before** this resource.

</details>

***

## Changelog

### v1.3.1

* Bug fixes and stability improvements

### v1.3.0

* Added QBox (QBx) framework support with ox\_lib integration
* Added modern JSON-based auto-updater system
* Removed legacy inline version check from framework files
* Optimized client marker loops (vector math, cached variables)
* Fixed `isBusy` variable casing inconsistency
* Fixed QB EMS count logic (job change tracking was inverted)
* Fixed blip names showing 'Heal' for revive points
* Added nil checks on server events
* Added `SetModelAsNoLongerNeeded` for NPC spawning
* Updated `isAllowedJobForPoint` for both string and table job data

### v1.2.0

* Major fix on EMS count for ESX + QBCore initial markers loading

### v1.1.1

* Distance check on /carry

### v1.1.0

* Reorganized configuration for unlimited map points
* Added configurable props, blips, and markers per point
* Added job restriction per point (illegal trades)

### v1.0.0

* Initial release

***

## Support

| Channel | Link                                                   |
| ------- | ------------------------------------------------------ |
| Discord | [discord.gg/9yY3Jxnhh8](https://discord.gg/9yY3Jxnhh8) |

***
