# LIFE INVADER

***

### 1) Overview

Risk Life Invader is a dynamic announcement system for FiveM servers featuring:

* 📢 Public or anonymous announcements
* 💰 Pay-per-character pricing system
* ⏱️ Configurable cooldown system
* 🚫 Word blacklist/filter
* 👮 Job-based announcements (Police, EMS, etc.)
* 📱 Automatic phone number detection
* 🔔 Discord webhook integration (public + admin logs)
* 🎨 Fully customizable UI with job-specific themes

***

### 2) Basic Configuration

#### Framework Detection

```lua
-- Framework is automatically detected (ESX, QBCore, QBox)
-- No manual configuration needed
```

#### Location Setup

```lua
RISK.Point = vector3(-1082.0703, -247.8123, 38.7633)
```

**Default location:** Life Invader Office in Downtown Los Santos\
**To get coordinates:** Stand where you want the location and use `/getcoords`

#### Interaction Range

```lua
RISK.Marker = {
    drawDist = 25.0,  -- Distance at which marker is visible
    useDist = 1.5     -- Distance required to interact (press E)
}
```

***

### 3) Pricing System

#### Basic Pricing

```lua
RISK.Price = {
    perChar = 5,              -- Price per character
    min = 0,                  -- Minimum price (even if message is short)
    max = 0,                  -- Maximum price (0 = no limit)
    countTitleInPrice = true  -- Include title in character count
}
```

**How it works:**

* Total characters = Message + Title (if `countTitleInPrice = true`)
* Cost = Total characters × `perChar`
* If cost < `min`, charge `min`
* If `max > 0` and cost > `max`, charge `max`

**Example calculations:**

**Example 1: Basic pricing**

```lua
RISK.Price = {
    perChar = 10,
    min = 0,
    max = 0,
    countTitleInPrice = true
}
-- Message: "Buy my car!" (12 chars)
-- Title: "FOR SALE" (8 chars)
-- Total: 20 chars × $10 = $200
```

**Example 2: With minimum**

```lua
RISK.Price = {
    perChar = 5,
    min = 100,  -- Minimum $100
    max = 0,
    countTitleInPrice = true
}
-- Message: "Hi" (2 chars)
-- Title: "" (0 chars)
-- Calculated: 2 × $5 = $10
-- Charged: $100 (minimum applies)
```

**Example 3: With maximum**

```lua
RISK.Price = {
    perChar = 10,
    min = 0,
    max = 500,  -- Maximum $500
    countTitleInPrice = true
}
-- Message: Very long message (80 chars)
-- Title: "IMPORTANT" (9 chars)
-- Calculated: 89 × $10 = $890
-- Charged: $500 (maximum applies)
```

**Example 4: Title excluded from price**

```lua
RISK.Price = {
    perChar = 5,
    min = 0,
    max = 0,
    countTitleInPrice = false  -- Title is free
}
-- Message: "Looking for mechanic" (20 chars)
-- Title: "MECHANIC NEEDED" (15 chars - NOT counted)
-- Total: 20 × $5 = $100
```

#### Pricing Strategies

**Free announcements:**

```lua
RISK.Price = { perChar = 0, min = 0, max = 0, countTitleInPrice = true }
```

**Flat rate ($100 per announcement):**

```lua
RISK.Price = { perChar = 0, min = 100, max = 100, countTitleInPrice = true }
```

**Expensive (discourage spam):**

```lua
RISK.Price = { perChar = 50, min = 500, max = 5000, countTitleInPrice = true }
```

**Cheap (encourage use):**

```lua
RISK.Price = { perChar = 2, min = 0, max = 200, countTitleInPrice = true }
```

***

### 4) Cooldown System

```lua
RISK.CooldownTime = 5 * 60 * 1000  -- 5 minutes in milliseconds
```

**How it works:**

* After sending an announcement, player must wait `CooldownTime` before sending another
* Cooldown is per-player (not global)
* Set to `0` to disable cooldown

**Time conversion:**

```lua
-- 1 minute = 1 * 60 * 1000 = 60000
-- 5 minutes = 5 * 60 * 1000 = 300000
-- 10 minutes = 10 * 60 * 1000 = 600000
-- 15 minutes = 15 * 60 * 1000 = 900000
-- 30 minutes = 30 * 60 * 1000 = 1800000
-- 1 hour = 60 * 60 * 1000 = 3600000

-- Disable cooldown
RISK.CooldownTime = 0
```

***

### 5) Blacklist / Word Filter

```lua
RISK.BlacklistedWords = {
    "nigger",
    "faggot",
    "hitler",
    -- Add your own words...
}
```

**How it works:**

* Checks both title and message for blacklisted words
* Case-insensitive (matches "HITLER", "hitler", "HiTlEr")
* If found, announcement is blocked and player is notified
* No charge if blocked

**To disable blacklist:**

```lua
RISK.BlacklistedWords = {}
```

**Adding custom words:**

```lua
RISK.BlacklistedWords = {
    -- Profanity
    "badword1",
    "badword2",
    
    -- Spam
    "free money",
    "duplication",
    "hack",
    
    -- Server-specific
    "rival server name",
    "competing server",
    
    -- Phrases (use exact phrase)
    "kill yourself",
    "admin abuse"
}
```

**Best practices:**

* Use lowercase only (script converts to lowercase)
* Add common variations
* Test your blacklist before going live
* Balance moderation with freedom of expression

***

### 6) Phone Number System

```lua
RISK.UsePhoneNumberInPublicAnnounce = true
RISK.DummyPhone = "555-0102"
```

**How it works:**

* **Public announcements:** Shows sender's real phone number (if available)
* **Anonymous announcements:** Shows "Anonymous" (no phone number)
* **Fallback:** If no phone found, shows `DummyPhone`

**Phone detection order:**

1. lb-phone export
2. roadphone export
3. qb-phone export
4. Framework's phone field (QBCore/ESX)
5. Database query (users.phone\_number / players.phone)
6. Fallback to `DummyPhone`

**Configuration options:**

**Show real phone numbers:**

```lua
RISK.UsePhoneNumberInPublicAnnounce = true
RISK.DummyPhone = "555-0102"  -- Fallback if phone not found
```

**Always use dummy phone (privacy):**

```lua
RISK.UsePhoneNumberInPublicAnnounce = false
RISK.DummyPhone = "555-LIFE"  -- Always shows this
```

**Custom fallback numbers:**

```lua
RISK.DummyPhone = "811-INVADER"  -- Creative
RISK.DummyPhone = "000-0000"     -- Hidden
RISK.DummyPhone = "123-4567"     -- Simple
```

***

### 7) Job Announcements System

```lua
RISK.JobNotify = {
    enabled = true,
    command = "job",
    allowed = {
        police = { label = "Police", style = "police" },
        ambulance = { label = "Ambulance", style = "ambulance" },
        taxi = { label = "Taxi", style = "taxi" }
    },
    titleFallback = true
}
```

**How it works:**

* Authorized jobs can send announcements via command
* Format: `/job Message text here`
* Format with title: `/job Title | Message text here`
* No cost for job announcements
* Custom styling per job type

**Command usage:**

```bash
# Simple message (title auto-filled with job label)
/job Traffic stop on route 68, expect delays

# With custom title
/job URGENT | Officer needs backup at Legion Square

# Multi-line equivalent
/job Medical Emergency | Paramedics responding to downtown area
```

**Configuration options:**

**Enable/disable system:**

```lua
RISK.JobNotify.enabled = true   -- Enable job announcements
RISK.JobNotify.enabled = false  -- Disable completely
```

**Change command:**

```lua
RISK.JobNotify.command = "announce"  -- Use /announce instead of /job
RISK.JobNotify.command = "alert"     -- Use /alert
RISK.JobNotify.command = "broadcast" -- Use /broadcast
```

**Adding more jobs:**

```lua
RISK.JobNotify.allowed = {
    police = { label = "LSPD", style = "police" },
    sheriff = { label = "BCSO", style = "police" },
    ambulance = { label = "EMS", style = "ambulance" },
    fire = { label = "Fire Department", style = "ambulance" },
    mechanic = { label = "Mechanic", style = "taxi" },
    taxi = { label = "Taxi", style = "taxi" },
    government = { label = "Government", style = "police" },
    realestate = { label = "Real Estate", style = "taxi" }
}
```

**Title fallback:**

```lua
RISK.JobNotify.titleFallback = true   -- Auto-fill title with job label if no title provided
RISK.JobNotify.titleFallback = false  -- No auto-fill (leave title empty)
```

**Style system:** The `style` parameter applies custom CSS styling:

* `"police"` — Blue theme
* `"ambulance"` — Red theme
* `"taxi"` — Yellow theme

***

### 8) Visual Configuration

#### Map Blip

```lua
RISK.Blip = {
    enabled = true,
    sprite = 521,
    color = 1,
    scale = 0.8,
    name = "Life Invader"
}
```

**Blip customization:**

* **sprite:** Icon type — [Blip Sprites](https://docs.fivem.net/docs/game-references/blips/)
* **color:** Color ID (0-85)
* **scale:** Size multiplier (0.5 = small, 1.5 = large)
* **name:** Text on map

**Popular sprites:**

```lua
sprite = 521  -- Life Invader (default)
sprite = 205  -- Broadcasting tower
sprite = 184  -- Announcement
sprite = 162  -- Information
```

#### 3D Marker

```lua
RISK.Marker = {
    enabled = true,
    type = 21,
    scale = vector3(0.3, 0.3, 0.3),
    color = {r = 255, g = 255, b = 0},
    drawDist = 25.0,
    useDist = 1.5
}
```

**Marker types:**

* `21` — Arrow pointing down (recommended)
* `1` — Cylinder
* `27` — Circle outline
* `29` — Flat circle

[Full Marker List](https://docs.fivem.net/docs/game-references/markers/)

**Color examples:**

```lua
-- Yellow (default)
color = {r = 255, g = 255, b = 0}

-- Red
color = {r = 255, g = 0, b = 0}

-- Blue
color = {r = 0, g = 100, b = 255}

-- Green
color = {r = 0, g = 255, b = 0}
```

***

### 9) Notification System

```lua
Config.UseCustomNotify = false
Config.UseCustomHelpNotify = false

Config.Functions = {
    ["notify"] = function(ntype, title, text, time)
        exports['risk-notify']:Notify({
            type = ntype or 'info',
            message = text,
            title = title or 'LIFE INVADER',
            duration = time or 10000
        })
    end,
    ["helpnotify"] = function(key, text)
        exports["risk-notify"]:HelpNotify(key, text)
    end,
}

RISK.Notify = {
    duration = 10000  -- Notification duration in milliseconds
}
```

**To use default notifications:**

```lua
Config.UseCustomNotify = false
Config.UseCustomHelpNotify = false
```

**To integrate other systems:**

**ox\_lib:**

```lua
Config.UseCustomNotify = true
Config.Functions = {
    ["notify"] = function(ntype, title, text, time)
        lib.notify({
            title = title,
            description = text,
            type = ntype,
            duration = time
        })
    end,
}
```

**mythic\_notify:**

```lua
Config.UseCustomNotify = true
Config.Functions = {
    ["notify"] = function(ntype, title, text, time)
        exports['mythic_notify']:DoHudText(ntype, text)
    end,
}
```

**t-notify:**

```lua
Config.UseCustomNotify = true
Config.Functions = {
    ["notify"] = function(ntype, title, text, time)
        exports['t-notify']:Custom({
            style = ntype,
            message = text,
            duration = time
        })
    end,
}
```

***

### 10) Text Localization

```lua
RISK.Locales = {
    open_menu_prompt = "to open Life Invader",
    not_enough_money = "You don't have enough money (%s via %s required).",
    blacklist_message = "Forbidden word: %s! Ad not sent.",
    cooldown_message = "You still have a cooldown of %s."
}
```

**Customizing messages:**

**German:**

```lua
RISK.Locales = {
    open_menu_prompt = "um Life Invader zu öffnen",
    not_enough_money = "Du hast nicht genug Geld (%s über %s benötigt).",
    blacklist_message = "Verbotenes Wort: %s! Nachricht nicht gesendet.",
    cooldown_message = "Du hast noch %s Abklingzeit."
}
```

**Spanish:**

```lua
RISK.Locales = {
    open_menu_prompt = "para abrir Life Invader",
    not_enough_money = "No tienes suficiente dinero (%s vía %s requerido).",
    blacklist_message = "Palabra prohibida: %s! Anuncio no enviado.",
    cooldown_message = "Todavía tienes %s de espera."
}
```

**French:**

```lua
RISK.Locales = {
    open_menu_prompt = "pour ouvrir Life Invader",
    not_enough_money = "Vous n'avez pas assez d'argent (%s via %s requis).",
    blacklist_message = "Mot interdit: %s! Annonce non envoyée.",
    cooldown_message = "Vous avez encore %s de temps d'attente."
}
```

***

### 11) UI Text Configuration

#### Main UI Headers

```lua
RISK.UI = {
    Title = "RISK SCRIPTS",
    Subtitle = "System"
}
```

#### Information Box

```lua
RISK.Info = {
    Title = "INFORMATIONS",
    Text = "You can send your advertisements anonymously or publicly. Charges are calculated per character. Please write responsibly."
}
```

#### Message Input Section

```lua
RISK.Message = {
    Title = "MESSAGE",
    Placeholder = "Your Title... (optional)",
    Description = "Write here...",
    PaymentLabels = { cash = "Cash", bank = "Bank" }
}
```

**Customization examples:**

**Roleplay server:**

```lua
RISK.UI = {
    Title = "LIFE INVADER",
    Subtitle = "Broadcasting"
}

RISK.Info = {
    Title = "GUIDELINES",
    Text = "All announcements are public record. Abuse of this system will result in consequences. Pricing: $5 per character."
}
```

**Community server:**

```lua
RISK.UI = {
    Title = "ANNOUNCEMENT BOARD",
    Subtitle = "Community Messages"
}

RISK.Info = {
    Title = "HOW IT WORKS",
    Text = "Share your message with everyone! Choose anonymous or public. Be respectful - all messages are logged."
}
```

***

### 12) Discord Webhooks

#### Public Webhook (Player Announcements)

```lua
WebhookConfig.Public = {
    Enabled = true,
    WebhookURL = "https://discord.com/api/webhooks/YOUR_WEBHOOK",
    Username = "LifeInvader",
    AvatarURL = "https://files.catbox.moe/rfmge1.webp",
    Color = 16711680,  -- Red
    EmbedTitle = "New LifeInvader Message",
    ThumbnailURL = "https://files.catbox.moe/wud9k5.png",
    FooterText = "Sent via LifeInvader",
}
```

**What it logs:**

* Announcement title and message
* Sender name (if public) or "Anonymous"
* Phone number (if public)
* Custom thumbnail and branding

#### Admin Webhook (Detailed Logs)

```lua
WebhookConfig.AdminLog = {
    Enabled = true,
    WebhookURL = "https://discord.com/api/webhooks/YOUR_ADMIN_WEBHOOK",
    Username = "ADMIN LOG - LifeInvader",
    AvatarURL = "https://files.catbox.moe/rfmge1.webp",
    Color = 8421504,  -- Gray
    EmbedTitle = "LOG: New LifeInvader Message",
    FooterText = "Server Logs"
}
```

**What it logs:**

* Full announcement details
* Sender's in-game name
* Server ID
* Discord mention (if linked)
* Phone number
* Cost and payment method
* Public or anonymous status

#### Job Colors

```lua
WebhookConfig.JobColors = {
    police = 0x2E8CFF,      -- Blue
    ambulance = 0xFF4444,   -- Red
    mechanic = 0xFFD700,    -- Gold
    government = 0x8B00FF,  -- Purple
    taxi = 0xFFF000         -- Yellow
}
```

**Adding custom colors:**

```lua
WebhookConfig.JobColors = {
    police = 0x0080FF,       -- Bright blue
    sheriff = 0x8B4513,      -- Brown
    ambulance = 0xFF0000,    -- Red
    fire = 0xFF4500,         -- Orange-red
    mechanic = 0x32CD32,     -- Lime green
    taxi = 0xFFFF00,         -- Yellow
    realestate = 0x9370DB,   -- Purple
    government = 0x4B0082    -- Indigo
}
```

#### Webhook Setup

**To get Discord webhook URL:**

1. Open Discord server settings
2. Go to "Integrations" → "Webhooks"
3. Click "New Webhook"
4. Name it (e.g., "LifeInvader Public" or "LifeInvader Admin")
5. Select channel
6. Copy webhook URL
7. Paste into config

**Best practices:**

* Use **separate webhooks** for public and admin logs
* Put admin logs in **staff-only channel**
* Put public logs in **community channel** (optional)
* Test webhooks before going live

**Color conversion:** Use hex colors with `0x` prefix:

```lua
Color = 0xFF0000    -- Red
Color = 0x00FF00    -- Green
Color = 0x0000FF    -- Blue
Color = 0xFFFF00    -- Yellow
Color = 0xFF00FF    -- Magenta
Color = 0x00FFFF    -- Cyan
```

Or use decimal:

```lua
Color = 16711680    -- Red (decimal of 0xFF0000)
```

***

### 13) UI Theming / Colors

Customize in `html/config.css`:

```css
:root {
    --main-color: #FDFE02;        /* Primary accent (yellow) */
    --main-color-2: #858603;      /* Secondary (darker yellow) */
    --main-color-3: rgba(120, 120, 63, 0.95);  /* Background overlay */
    --main-color-4: rgba(63, 67, 39, 0.5795);  /* Darker overlay */
    --main-color-5: rgba(172, 174, 74, 0.95);  /* Highlight */
}
```

#### Job-Specific Themes

```css
.job-police {
    --job-bg1: rgba(10, 30, 70, 0.55);    /* Dark blue background */
    --job-bg2: rgba(45, 115, 255, 0.65);  /* Light blue overlay */
    --job-accent: #2E8CFF;                /* Blue accent */
}

.job-ambulance {
    --job-bg1: rgba(80, 0, 10, 0.55);     /* Dark red background */
    --job-bg2: rgba(255, 80, 80, 0.65);   /* Light red overlay */
    --job-accent: #FF4444;                /* Red accent */
}

.job-taxi {
    --job-bg1: rgba(70, 60, 0, 0.55);     /* Dark yellow background */
    --job-bg2: rgba(255, 215, 0, 0.65);   /* Light yellow overlay */
    --job-accent: #FFD700;                /* Gold accent */
}
```

#### Theme Examples

**Red/Black Theme (Aggressive):**

```css
:root {
    --main-color: #FF0000;
    --main-color-2: #CC0000;
    --main-color-3: rgba(139, 0, 0, 0.95);
    --main-color-4: rgba(70, 0, 0, 0.58);
    --main-color-5: rgba(200, 0, 0, 0.95);
}
```

**Blue Theme (Professional):**

```css
:root {
    --main-color: #00B4FF;
    --main-color-2: #0080CC;
    --main-color-3: rgba(0, 100, 180, 0.95);
    --main-color-4: rgba(0, 50, 90, 0.58);
    --main-color-5: rgba(50, 150, 255, 0.95);
}
```

**Green Theme (Money/Business):**

```css
:root {
    --main-color: #00FF00;
    --main-color-2: #00CC00;
    --main-color-3: rgba(0, 139, 0, 0.95);
    --main-color-4: rgba(0, 70, 0, 0.58);
    --main-color-5: rgba(50, 205, 50, 0.95);
}
```

**Purple Theme (Elite/VIP):**

```css
:root {
    --main-color: #9B59B6;
    --main-color-2: #8E44AD;
    --main-color-3: rgba(142, 68, 173, 0.95);
    --main-color-4: rgba(70, 30, 90, 0.58);
    --main-color-5: rgba(155, 89, 182, 0.95);
}
```

***

### 14) Complete Configuration Examples

#### Example 1: Free Community Board

```lua
-- No costs, no cooldowns, anyone can post
RISK.Price = {
    perChar = 0,
    min = 0,
    max = 0,
    countTitleInPrice = true
}

RISK.CooldownTime = 0  -- No cooldown

RISK.BlacklistedWords = {
    -- Minimal moderation
    "extreme profanity",
}

RISK.JobNotify.enabled = false  -- Community only, no job announcements
```

#### Example 2: Serious RP Server

```lua
-- Expensive announcements, strict moderation
RISK.Price = {
    perChar = 20,
    min = 500,
    max = 5000,
    countTitleInPrice = true
}

RISK.CooldownTime = 30 * 60 * 1000  -- 30 minute cooldown

RISK.BlacklistedWords = {
    -- Extensive list
    "profanity",
    "spam words",
    "server advertising",
    -- ...many more
}

RISK.JobNotify.enabled = true
RISK.JobNotify.allowed = {
    police = { label = "LSPD", style = "police" },
    sheriff = { label = "BCSO", style = "police" },
    ambulance = { label = "EMS", style = "ambulance" }
}
```

#### Example 3: Economy Server (Paid Ads)

```lua
-- Moderate pricing, encourages business
RISK.Price = {
    perChar = 10,
    min = 100,
    max = 1000,
    countTitleInPrice = true
}

RISK.CooldownTime = 10 * 60 * 1000  -- 10 minutes

RISK.UsePhoneNumberInPublicAnnounce = true  -- Show contacts

RISK.BlacklistedWords = {
    "free money",
    "duplication",
    "hack"
}

WebhookConfig.Public.Enabled = true  -- Public announcements in Discord
```

#### Example 4: Casual Server (Easy & Fun)

```lua
-- Cheap, fast, fun
RISK.Price = {
    perChar = 2,
    min = 0,
    max = 200,
    countTitleInPrice = false  -- Title is free
}

RISK.CooldownTime = 2 * 60 * 1000  -- 2 minutes

RISK.BlacklistedWords = {
    -- Basic moderation only
}

RISK.JobNotify.enabled = true
RISK.JobNotify.allowed = {
    police = { label = "Police", style = "police" },
    ambulance = { label = "Medic", style = "ambulance" },
    mechanic = { label = "Mechanic", style = "taxi" },
    taxi = { label = "Taxi", style = "taxi" }
}
```

***

### 15) Troubleshooting

#### ❌ "You don't have enough money"

**Cause:** Player doesn't have sufficient cash/bank balance\
**Solution:**

* Lower `RISK.Price.perChar`
* Lower or remove `RISK.Price.min`
* Test with `/givemoney [id] 10000`

#### ❌ "You still have a cooldown of X"

**Cause:** Player sent announcement recently\
**Solution:**

* Lower `RISK.CooldownTime`
* Set to `0` to disable
* Restart resource to clear cooldowns

#### ❌ "Forbidden word: X! Ad not sent."

**Cause:** Message contains blacklisted word\
**Solution:**

* Remove word from `RISK.BlacklistedWords`
* Use different wording
* Disable blacklist: `RISK.BlacklistedWords = {}`

#### ❌ Phone number shows as "555-0102"

**Possible causes:**

* Phone resource not installed/started
* Player doesn't have phone number assigned
* Phone resource not compatible

**Solution:**

* Install compatible phone resource (lb-phone, qb-phone, roadphone)
* Assign phone numbers to players
* Change `RISK.DummyPhone` to preferred fallback

#### ❌ UI won't open

**Possible causes:**

* Too far from location
* Marker/blip disabled
* Conflicting resource

**Solution:**

* Stand directly on `RISK.Point` location
* Enable marker: `RISK.Marker.enabled = true`
* Check console for errors (F8)
* Restart resource: `/restart risk-lifeinvader`

#### ❌ Job command not working

**Possible causes:**

* `RISK.JobNotify.enabled = false`
* Player's job not in `allowed` list
* Wrong command name

**Solution:**

* Set `RISK.JobNotify.enabled = true`
* Add job to `RISK.JobNotify.allowed`
* Check command: `RISK.JobNotify.command`
* Verify player has correct job

#### ❌ Notifications not showing to other players

**Possible causes:**

* Script not started properly
* Client-side error
* Custom notification issue

**Solution:**

* Restart resource
* Check all player consoles (F8)
* Test with `Config.UseCustomNotify = false`

#### ❌ Discord webhooks not sending

**Possible causes:**

* Invalid webhook URL
* Webhook deleted from Discord
* `Enabled = false`

**Solution:**

* Create new webhook
* Copy full URL including `/12345/token`
* Set `WebhookConfig.Public.Enabled = true`
* Set `WebhookConfig.AdminLog.Enabled = true`

#### ❌ Announcements show wrong phone number

**Cause:** Phone detection not working\
**Solution:**

* Verify phone resource is started
* Check phone resource exports
* Set custom `RISK.DummyPhone`
* Or disable: `RISK.UsePhoneNumberInPublicAnnounce = false`

***

### 16) Best Practices

✅ **Balance pricing with server economy** — Don't make too expensive or too cheap\
✅ **Use cooldowns to prevent spam** — 5-15 minutes recommended\
✅ **Maintain blacklist regularly** — Add problematic words as they appear\
✅ **Test job announcements** — Ensure all jobs can use the system\
✅ **Use webhooks for moderation** — Monitor admin logs channel\
✅ **Keep UI text clear** — Explain pricing and rules in info box\
✅ **Test phone integration** — Verify phone numbers display correctly\
✅ **Customize themes** — Match your server's branding\
✅ **Monitor usage patterns** — Adjust pricing based on activity\
✅ **Communicate changes** — Tell players about pricing/cooldown updates

***

### 17) Quick Start Checklist

* \[ ] Set location: `RISK.Point`
* \[ ] Configure pricing: `RISK.Price`
* \[ ] Set cooldown: `RISK.CooldownTime`
* \[ ] Add blacklisted words: `RISK.BlacklistedWords`
* \[ ] Enable/configure job announcements: `RISK.JobNotify`
* \[ ] Set phone number options: `RISK.UsePhoneNumberInPublicAnnounce`
* \[ ] Configure Discord webhooks (optional)
* \[ ] Customize UI text: `RISK.UI`, `RISK.Info`, `RISK.Message`
* \[ ] Customize colors in `config.css` (optional)
* \[ ] Test with multiple players
* \[ ] Restart resource: `/restart risk-lifeinvader`

***

### 18) How It Works

#### Announcement Flow

1. **Player approaches location** → Sees marker/blip
2. **Presses E** → Opens UI with tablet animation
3. **Writes message** → Price updates live based on character count
4. **Chooses public/anonymous** → Preview updates
5. **Selects payment method** → Cash or bank
6. **Clicks "Send Announcement"** → Server validates and charges
7. **Checks blacklist & cooldown** → Blocks if violation
8. **Broadcasts to all players** → In-game notification appears
9. **Logs to Discord** → Admin and public webhooks (if enabled)
10. **Player enters cooldown** → Must wait before next announcement

#### Job Announcement Flow

1. **Authorized player types command** → `/job Message here`
2. **Server validates job** → Checks if job is in `allowed` list
3. **No cost charged** → Job announcements are free
4. **Broadcasts with custom style** → Uses job-specific theme colors
5. **Logs to Discord** → Includes job information

#### Security Features

* ✅ Server-side money validation
* ✅ Server-side blacklist checking
* ✅ Server-side cooldown tracking
* ✅ Price calculated server-side (not in UI)
* ✅ Job permissions verified server-side
* ✅ Discord logging for admin oversight

***


---

# 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://risk-scripts.gitbook.io/risk-scripts/scripts/life-invader.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.
