# Events

## 🪂 Airdrop Event

A supply crate drops at a random location on the map. Players race to find it and crack the safe to claim valuable rewards.

### How It Works

1. A random location is selected from the configured locations list
2. A flare appears in the sky and smoke rises from the ground
3. A military crate prop spawns at the location
4. A flashing blip appears on everyone's map
5. A cinematic announcement displays on all screens
6. Players navigate to the location
7. Within 5 meters, a 3D text prompt appears: \[E] Open Crate (30s)
8. Pressing E starts the safe cracking animation with a progress bar
9. Cracking is cancelled if the player moves away or dies
10. First player to complete cracking receives the reward
11. Event ends 10 seconds after claiming
12. If nobody claims within the duration, the event expires

### Configuration

#### General Settings

| Setting              | Type    | Default | Description                        |
| -------------------- | ------- | ------- | ---------------------------------- |
| `enabled`            | boolean | `true`  | Enable this event type             |
| `duration`           | number  | `15`    | Event duration in minutes          |
| `crackTime`          | number  | `30`    | Time to crack the safe in seconds  |
| `minDistanceBetween` | number  | `500.0` | Minimum distance from other events |

#### Blip Settings

| Setting      | Type    | Default | Description          |
| ------------ | ------- | ------- | -------------------- |
| `blipColor`  | number  | `1`     | Blip color (1 = Red) |
| `blipSprite` | number  | `484`   | Blip icon sprite     |
| `blipScale`  | number  | `1.2`   | Blip size on map     |
| `blipFlash`  | boolean | `true`  | Blip flashes on map  |

#### Effect Settings

| Setting        | Type    | Default             | Description              |
| -------------- | ------- | ------------------- | ------------------------ |
| `flareEnabled` | boolean | `true`              | Show sky flare effect    |
| `smokeEnabled` | boolean | `true`              | Show ground smoke effect |
| `smokeColor`   | table   | `{r=255, g=0, b=0}` | Smoke RGB color          |

#### Full Config Example

```lua
Config.Airdrop = {
    enabled = true,
    duration = 15,
    blipColor = 1,
    blipSprite = 484,
    blipScale = 1.2,
    blipFlash = true,
    crackTime = 30,
    flareEnabled = true,
    smokeEnabled = true,
    smokeColor = {r = 255, g = 0, b = 0},
    minDistanceBetween = 500.0,
    rewards = {
        {
            label = 'Low Value',
            chance = 50,
            items = {
                { name = 'bread',   count = 5, label = 'Bread' },
                { name = 'water',   count = 5, label = 'Water' },
                { name = 'bandage', count = 3, label = 'Bandage' },
            },
            money = { min = 1000, max = 3000 },
        },
        {
            label = 'Medium Value',
            chance = 35,
            items = {
                { name = 'lockpick', count = 2, label = 'Lockpick' },
                { name = 'radio',    count = 1, label = 'Radio' },
                { name = 'armor',    count = 1, label = 'Armor' },
            },
            money = { min = 5000, max = 10000 },
        },
        {
            label = 'High Value',
            chance = 15,
            items = {
                { name = 'weapon_pistol', count = 1, label = 'Pistol' },
                { name = 'ammo_9',        count = 50, label = '9mm Ammo' },
            },
            money = { min = 15000, max = 30000 },
        },
    },
    locations = {
        { coords = vector3(228.0, -3154.0, 5.8),    label = 'Port Area' },
        { coords = vector3(1538.0, 6323.0, 24.0),   label = 'Paleto Bay' },
        { coords = vector3(-1037.0, -2736.0, 20.0), label = 'Airport' },
        { coords = vector3(2536.0, -384.0, 92.0),   label = 'Vinewood Hills' },
        { coords = vector3(-66.0, 6262.0, 31.0),    label = 'North Highway' },
        { coords = vector3(1651.0, -1.0, 166.0),    label = 'Mountain Top' },
        { coords = vector3(-1613.0, -1050.0, 13.0), label = 'Del Perro Beach' },
        { coords = vector3(802.0, -2157.0, 29.0),   label = 'Industrial Zone' },
    },
}
```

### Reward System

Rewards use weighted random selection. Each tier has a chance value that determines probability.

| Tier         | Chance | Probability |
| ------------ | ------ | ----------- |
| Low Value    | 50     | 50%         |
| Medium Value | 35     | 35%         |
| High Value   | 15     | 15%         |

Each tier gives both items and a random money amount between min and max.

***

### Adding Locations

Add new locations to the locations table:

```
{ coords = vector3(X, Y, Z), label = 'Location Name' },
```

Tips:

* Choose flat, accessible outdoor areas
* Avoid interiors or underground locations
* Test that the prop spawns correctly on the ground
* Spread locations across the map for variety

***

### Security

| Check     | Location | Description                            |
| --------- | -------- | -------------------------------------- |
| Distance  | Server   | Player must be within 10m to claim     |
| Duplicate | Server   | Claimed flag prevents double claims    |
| Death     | Client   | Cracking cancelled when player dies    |
| Movement  | Client   | Cracking cancelled if player moves >5m |

## 🔥 Hotzone Event

A circular zone appears on the map. Players who stay inside earn rewards every tick interval.

***

### How It Works

1. A random location is selected with a configurable radius
2. A radius blip shows the zone boundary on the map
3. 8 flare particles mark the zone edges
4. A cinematic announcement displays on all screens
5. Players entering the zone get a notification and screen effect
6. Every reward interval, players inside receive money and items
7. Leaving the zone stops rewards and clears the screen effect
8. Event ends when the duration runs out

### Configuration

#### General Settings

| Setting            | Type    | Default | Description                  |
| ------------------ | ------- | ------- | ---------------------------- |
| `enabled`          | boolean | `true`  | Enable this event type       |
| `duration`         | number  | `10`    | Event duration in minutes    |
| `radius`           | number  | `100.0` | Zone radius in meters        |
| `rewardInterval`   | number  | `60`    | Seconds between reward ticks |
| `pvpEnabled`       | boolean | `true`  | Allow PvP inside the zone    |
| `maxPlayersReward` | number  | `10`    | Max players earning per tick |

#### Blip Settings

| Setting      | Type   | Default | Description              |
| ------------ | ------ | ------- | ------------------------ |
| `blipColor`  | number | `17`    | Blip color (17 = Orange) |
| `blipSprite` | number | `458`   | Blip icon sprite         |
| `blipScale`  | number | `1.5`   | Blip size on map         |

#### Full Config Example

```lua
Config.Hotzone = {
    enabled = true,
    duration = 10,
    radius = 100.0,
    blipColor = 17,
    blipSprite = 458,
    blipScale = 1.5,
    rewardInterval = 60,
    rewardPerTick = {
        money = { min = 500, max = 1500 },
        items = {
            { name = 'bread', count = 1, chance = 30 },
            { name = 'bandage', count = 1, chance = 20 },
        },
    },
    pvpEnabled = true,
    maxPlayersReward = 10,
    locations = {
        { coords = vector3(103.0, -1941.0, 20.0),   label = 'Davis' },
        { coords = vector3(325.0, -2039.0, 20.0),   label = 'Strawberry' },
        { coords = vector3(-1205.0, -1557.0, 4.0),  label = 'Beachside' },
        { coords = vector3(1163.0, -1340.0, 34.0),  label = 'Mirror Park' },
        { coords = vector3(-246.0, -983.0, 29.0),   label = 'City Center' },
    },
}
```

### Reward Per Tick

Every rewardInterval seconds, each player inside the zone receives:

**Money:** Random amount between min and max

```
money = { min = 500, max = 1500 },
```

**Items:** Each item has an independent chance to drop per tick

```
items = {
    { name = 'bread', count = 1, chance = 30 },
    { name = 'bandage', count = 1, chance = 20 },
},
```

Example earnings for 10 minutes with 60s interval:

* 10 ticks x $500-$1500 = $5,000 - $15,000 per player
* Plus random item drops each tick

***

### Security

| Check            | Location | Description                                 |
| ---------------- | -------- | ------------------------------------------- |
| Enter validation | Server   | Distance check with +10m tolerance          |
| Tick validation  | Server   | Distance re-checked every reward tick       |
| Auto-remove      | Server   | Offline players removed from zone list      |
| Player tracking  | Server   | playersInZone table maintained server-side  |
| Max cap          | Server   | Only maxPlayersReward players earn per tick |

## 🚛 Convoy Event

An armored cargo vehicle drives along a predetermined route. Players must destroy it to claim valuable rewards.

### How It Works

1. A cargo vehicle spawns at the configured spawn point
2. A driver NPC and optional armed passengers are placed inside
3. A moving blip tracks the vehicle on the map
4. The vehicle follows waypoints along the configured route
5. NPCs are initially neutral - they do not attack anyone
6. When the vehicle or NPCs take weapon damage:
   * NPCs become hostile (provoked state)
   * Vehicle speed increases
   * Vehicle mass increases to ram through obstacles
   * Passengers open fire with driveby attacks
   * Passengers may exit the vehicle and fight on foot
7. Vehicle is destroyed when health drops below thresholds
8. The destroying player receives money and item rewards
9. If not destroyed in time, the convoy escapes

### Configuration

#### Vehicle Settings

| Setting             | Type    | Default      | Description                    |
| ------------------- | ------- | ------------ | ------------------------------ |
| `cargoModel`        | string  | `'stockade'` | Vehicle model name             |
| `cargoEngineHealth` | number  | `300.0`      | Starting engine health         |
| `cargoBodyHealth`   | number  | `300.0`      | Starting body health           |
| `fillAllSeats`      | boolean | `false`      | Fill all seats with armed NPCs |

#### Speed Settings

| Setting         | Type   | Default   | Description                         |
| --------------- | ------ | --------- | ----------------------------------- |
| `cargoSpeed`    | number | `12.0`    | Normal driving speed (\~45 km/h)    |
| `provokedSpeed` | number | `22.0`    | Speed when under attack (\~80 km/h) |
| `provokedMass`  | number | `10000.0` | Vehicle mass when provoked          |

#### NPC Settings

| Setting        | Type   | Default           | Description                 |
| -------------- | ------ | ----------------- | --------------------------- |
| `npc.model`    | string | `'s_m_y_swat_01'` | NPC ped model               |
| `npc.health`   | number | `400`             | NPC health points           |
| `npc.armor`    | number | `100`             | NPC armor points            |
| `npc.accuracy` | number | `50`              | Shooting accuracy (0-100)   |
| `npc.weapons`  | table  | `{...}`           | Weapons given to passengers |

#### Full Config Example

```lua
Config.Convoy = {
    enabled = true,
    duration = 15,
    blipColor = 5,
    blipSprite = 326,
    blipScale = 1.0,
    cargoModel = 'stockade',
    spawnPoints = {
        cargo = { coords = vector3(163.0, -3188.0, 5.9), heading = 270.0 },
    },
    cargoEngineHealth = 300.0,
    cargoBodyHealth = 300.0,
    cargoSpeed = 12.0,
    provokedSpeed = 22.0,
    provokedMass = 10000.0,
    fillAllSeats = false,
    npc = {
        model = 's_m_y_swat_01',
        health = 400,
        armor = 100,
        accuracy = 50,
        weapons = { 'WEAPON_CARBINERIFLE', 'WEAPON_PISTOL' },
    },
    rewards = {
        items = {
            { name = 'goldbar', count = 2, label = 'Gold Bar' },
            { name = 'diamond', count = 1, label = 'Diamond' },
        },
        money = { min = 20000, max = 50000 },
    },
    routes = {
        {
            label = 'Port to Bank',
            points = {
                vector3(163.0, -3188.0, 5.9),
                vector3(-29.0, -2430.0, 6.0),
                vector3(213.0, -1643.0, 29.0),
                vector3(150.0, -1040.0, 29.0),
                vector3(237.0, 217.0, 106.0),
            },
        },
        {
            label = 'North to South',
            points = {
                vector3(1692.0, 4784.0, 41.9),
                vector3(1660.0, 3551.0, 35.3),
                vector3(1295.0, 1137.0, 82.0),
                vector3(530.0, -170.0, 54.0),
                vector3(237.0, 217.0, 106.0),
            },
        },
    },
}
```

### Provoke System

The convoy starts neutral. NPCs will not attack until provoked.

**Triggers provoke:**

* Vehicle engine or body health drops by more than 10 points
* Any NPC loses health

**Does NOT trigger provoke:**

* Driving near the convoy
* Minor vehicle collisions (less than 10 health loss)
* Standing near the convoy

**When provoked:**

* Relationship changes from neutral to hostile
* Vehicle speed increases to provokedSpeed
* Vehicle mass increases to provokedMass
* Passengers open fire with driveby attacks
* Passengers may exit and fight on foot
* Drivers continue driving the route

***

### Destruction Conditions

The convoy is destroyed when ANY of these are true:

| Condition                    | Threshold |
| ---------------------------- | --------- |
| Engine health                | ≤ 300     |
| Body health                  | ≤ 300     |
| Total health (engine + body) | ≤ 700     |

Shooting any part of the vehicle counts as damage.

***

### Route Tips

* Use coordinates on roads, not off-road
* Space waypoints at reasonable intervals
* First waypoint should match the spawn point
* More waypoints create smoother paths
* Test routes to ensure AI can follow them

***

### Stuck Detection

If the vehicle speed stays below 1.0 for 10 seconds:

1. Vehicle reverses for 3 seconds
2. Re-attempts driving to the current waypoint

## 🗺️ Treasure Hunt Event

A treasure is buried at a secret location. Players use a signal detector to find it. This is the most secure event - actual coordinates are NEVER sent to the client.

### How It Works

1. Server selects a random treasure location (kept server-side only)
2. A fake offset search center is sent to clients
3. A radius blip shows the approximate search zone
4. Players move around and request signal strength from the server
5. Server calculates distance and returns signal percentage and direction
6. A signal HUD bar appears showing signal strength
7. Direction arrows guide players (N/S/E/W)
8. Periodic hints shrink the search area over time
9. When within 3 meters, pressing E sends a dig request to server
10. Server validates actual distance before allowing dig
11. Digging animation plays with particles and progress bar
12. First player to finish digging claims the reward

### Security Architecture

```
Traditional (insecure):
Server sends actual coords to client
Cheater reads memory and finds coords instantly
```

```
EL_EVENTS (secure):
Client asks: "How close am I?"
Server checks real distance, sends back only signal %
Client NEVER knows actual coordinates
```

| Data                                  | Sent to Client |
| ------------------------------------- | -------------- |
| Actual treasure coordinates           | ❌ NEVER        |
| Signal strength (0-100%)              | ✅ Yes          |
| Direction (N/S/E/W)                   | ✅ Yes          |
| Can dig permission (true/false)       | ✅ Yes          |
| Approximate distance (when under 50m) | ✅ Yes          |
| Search center (offset from actual)    | ✅ Yes          |

***

### Configuration

#### General Settings

| Setting        | Type    | Default | Description                 |
| -------------- | ------- | ------- | --------------------------- |
| `enabled`      | boolean | `true`  | Enable this event type      |
| `duration`     | number  | `12`    | Event duration in minutes   |
| `searchRadius` | number  | `200.0` | Initial search area radius  |
| `digTime`      | number  | `10`    | Digging duration in seconds |

#### Hint System

| Setting              | Type    | Default | Description               |
| -------------------- | ------- | ------- | ------------------------- |
| `hints.enabled`      | boolean | `true`  | Enable periodic hints     |
| `hints.interval`     | number  | `120`   | Seconds between hints     |
| `hints.maxHints`     | number  | `3`     | Maximum number of hints   |
| `hints.shrinkRadius` | number  | `50.0`  | Radius reduction per hint |

#### Full Config Example

```lua
Config.TreasureHunt = {
    enabled = true,
    duration = 12,
    searchRadius = 200.0,
    blipColor = 25,
    blipSprite = 378,
    blipScale = 1.5,
    hints = {
        enabled = true,
        interval = 120,
        maxHints = 3,
        shrinkRadius = 50.0,
    },
    digTime = 10,
    digAnim = {
        dict = 'amb@world_human_gardener_plant@male@base',
        name = 'base',
    },
    rewards = {
        { name = 'goldbar',  count = 3, chance = 20, label = 'Gold Bar' },
        { name = 'diamond',  count = 2, chance = 15, label = 'Diamond' },
        { name = 'lockpick', count = 5, chance = 30, label = 'Lockpick' },
        { name = 'money',    count = 0, chance = 35, label = 'Cash',
            money = { min = 10000, max = 25000 }
        },
    },
    locations = {
        { coords = vector3(2557.0, 4658.0, 33.9),   label = 'Desert Area' },
        { coords = vector3(-1884.0, 2034.0, 140.0),  label = 'Mountain Base' },
        { coords = vector3(1290.0, 4316.0, 37.0),    label = 'Grapeseed' },
        { coords = vector3(-1109.0, 4919.0, 218.0),  label = 'Raton Canyon' },
        { coords = vector3(2397.0, 3064.0, 48.0),    label = 'Highway Side' },
        { coords = vector3(-862.0, 5403.0, 34.0),    label = 'Paleto Forest' },
    },
}
```

### Signal System

#### Signal Strength Formula

```lua
signal = max(0, min(100, floor((1 - distance / maxRange) * 100)))
```

| Signal | Meaning         | Visual                           |
| ------ | --------------- | -------------------------------- |
| 0%     | Out of range    | No HUD shown                     |
| 1-29%  | Weak signal     | Purple bar                       |
| 30-59% | Signal detected | Purple bar with direction        |
| 60-89% | Getting warmer  | Orange indicator with beeps      |
| 90-99% | Very close      | Green indicator with rapid beeps |
| 100%   | On top of it    | Can dig prompt appears           |

#### Direction System

Server calculates cardinal direction from player to treasure:

| Code | Direction  | When                                          |
| ---- | ---------- | --------------------------------------------- |
| N    | ↑ Go North | Treasure is north (Y diff dominant, positive) |
| S    | ↓ Go South | Treasure is south (Y diff dominant, negative) |
| E    | → Go East  | Treasure is east (X diff dominant, positive)  |
| W    | ← Go West  | Treasure is west (X diff dominant, negative)  |

***

### Hint Timeline

With default settings:

| Time  | Event                          |
| ----- | ------------------------------ |
| 0:00  | Hunt starts with 200m radius   |
| 2:00  | Hint 1: Radius shrinks to 150m |
| 4:00  | Hint 2: Radius shrinks to 100m |
| 6:00  | Hint 3: Radius shrinks to 50m  |
| 12:00 | Hunt expires if not found      |

Each hint also moves the search center closer to the actual location.

***

### Security Checks

| Check            | Location | When                | Description                  |
| ---------------- | -------- | ------------------- | ---------------------------- |
| Signal calc      | Server   | Every 1 second      | Distance checked server-side |
| Dig permission   | Server   | On E press          | Must be within 5m            |
| Claim validation | Server   | On dig complete     | Must be within 8m            |
| Cheat logging    | Server   | On suspicious claim | Distance logged              |
| Coords hidden    | Server   | Always              | Never sent to client         |


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://elena-scripts.gitbook.io/elenascripts/core-systems/el-events/events.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
