> For the complete documentation index, see [llms.txt](https://rtx-dev.gitbook.io/rtxdev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://rtx-dev.gitbook.io/rtxdev/ghost-hunting.md).

# Ghost Hunting

{% embed url="<https://www.youtube.com/watch?v=VSlB9Xv4kHI>" %}

## Purchase

[Purchase this resource](https://rtx.tebex.io/package/7710806)

**RTX Ghost Hunting** turns any building on your FiveM server into a haunted house. A team takes a case from the ghost hunter, walks into a house with the power out and has to work out **which of 10 ghosts** lives there. They find its room with the thermometer and the EMF reader, collect evidence with the spirit box, the camera, the writing book and the silhouette projector, mark it in a shared journal, photograph the ghost and get back out alive. The lower their sanity, the more the ghost does - until it starts hunting them.

Every house is built **in game** with the location creator, every ghost, event, object and reward is in the config, and everything the team sees is synchronized between the players.

## Features

* **Co-op investigations** - a team with a leader, invites, a lobby and its own HUD, or hunt alone
* **10 ghost types** - every one with its own evidence and its own behaviour, and you can add your own
* **6 types of evidence** - EMF level 5, freezing temperature, orbs on camera, spirit box, ghost writing, projector silhouette
* **Investigation tools** - thermometer, EMF reader, spirit box, camera with night vision and zoom, flashlight, writing book, silhouette projector
* **Sanity** - drains while you are inside, faster in the ghost's room and alone; the lower it is, the more active the ghost
* **19 ghost events** - thrown objects, slamming doors, knocks, footsteps, whispers, flickering lights, the ghost showing itself, walking past, blowing the fuse and more
* **Hunts** - exit doors lock, lightning hits, the ghost walks the house looking for the team; hide in a wardrobe or get caught
* **7 jumpscares** with a cinematic camera, and **hallucinations** at low sanity, including fake hunts
* **Haunted objects** - ghost board, tarot cards, voodoo doll, music box, Bloody Mary mirror, phone, radio, TV, coffin, cursed teddy, old diary, fuse box, rats, rocking chair
* **Interactive houses** - lamps, light switches, candles, bulbs that burst, wardrobes to hide in
* **Shared journal** - evidence, all ghosts, what happened, objectives, equipment, haunted items, photos and the team
* **3 difficulties** - Easy, Normal and Nightmare, or your own
* **Bonus objectives** - picked at random every run, each with its own reward
* **Rewards** - money and items, itemised in the investigation report
* **Leaderboard** - solved, hunts, fastest solve and money earned
* **Spectating** - a caught player watches his team
* **House mode or city mode** - a ghost hunter at every house, or a case board in the city and a drive to the house
* **In-game location creator** - rooms, ghost spots, doors, barriers, objects, lights, IPL interiors, no config editing, no restart
* **Scene mode** - pose ghosts and hunters for screenshots and trailers
* **Two interface styles** - paper case files or a dark modern interface
* **Access control** - open to everybody, or only a job, an ACE, groups, single players or an item
* **Own instance for every team**, or one team per house that everybody can see
* **Fully synchronized**
* **18 languages**
* **ESX, QBCore, QBox and standalone**

## Requirements

| Resource                             | Required                                                                                                                       |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
| `rtx_ghost`                          | Yes - the script, the tool models and the haunted objects are inside it                                                        |
| OneSync                              | Yes - every team hunts in its own routing bucket                                                                               |
| `oxmysql`                            | No - recommended. Houses and the leaderboard are saved in the database. Without it they are saved in files inside the resource |
| `screenshot-basic`                   | No - only for photos in the journal and photos of the houses on the case board                                                 |
| `ox_inventory` / framework inventory | No - only for reward items and the access item                                                                                 |
| Ambulance script                     | No - `wasabi_ambulance`,  `qb-ambulancejob` and `esx_ambulancejob` are picked up on their own                                  |

## Installation

{% hint style="info" %}
**Framework compatibility**

This resource is **standalone** and works on any FiveM server.

Compatible with **ESX**, **QBCore**, **QBox**, **vRP**, and other frameworks.

If you are using a framework other than ESX, QBCore, or QBox, follow the **Standalone** installation instructions.
{% endhint %}

{% stepper %}
{% step %}

### Add the resource

Place `rtx_ghost` into your resources folder and add it to your `server.cfg`, after your framework, your inventory and `oxmysql`:

```
ensure rtx_ghost
```

{% hint style="warning" %}
Keep the `stream` folder and the `data` folder. The `stream` folder holds the tools and the haunted objects, the `data` folder holds the houses when you use file storage.
{% endhint %}
{% endstep %}

{% step %}

### Framework

Open `config.lua`, section 1:

```lua
Config.Framework = "esx" -- "esx", "qbcore" or "standalone"

Config.Frameworks = {
	esx = {
		resource = "es_extended",
		newversion = true,
		getsharedobject = "esx:getSharedObject"
	},

	qbcore = {
		resource = "qb-core"
	}
}

Config.Inventory = {
	system = "ox", -- "ox" for ox_inventory, "framework" for the one your framework ships with
	qbnewversion = false -- QBCore with system = "framework" only. true for the newer qb-inventory
}
```

| Framework          | Value          |
| ------------------ | -------------- |
| ESX                | `"esx"`        |
| QBCore / QBox      | `"qbcore"`     |
| Standalone / other | `"standalone"` |

{% hint style="info" %}
In standalone mode nothing is paid out, unless you fill in `AddMoneyRTX` in `server/other.lua`. Use the ESX and QBCore parts in the same file as reference.
{% endhint %}
{% endstep %}

{% step %}

### Storage

```lua
Config.Storage = {
	mode = "database", -- "database" or "file"
	resource = "oxmysql"
}
```

With `"database"` the tables `rtx_ghost_locations` and `rtx_ghost_stats` are created on their own - **nothing to import**. See [Storage](#storage).
{% endstep %}

{% step %}

### Admins

The location creator belongs to whoever your `server.cfg` gives `ghostcreator.use` to:

```
add_ace group.admin ghostcreator.use allow
```

Framework groups, a builder job and single players by identifier can be allowed too, see [Permissions](#permissions).
{% endstep %}

{% step %}

### Build your first house

Walk into any building and type `/ghostcreator`. See [Location Creator](#location-creator).
{% endstep %}
{% endstepper %}

## How an Investigation Works

{% stepper %}
{% step %}

### Take the case

Walk up to the ghost hunter and press `E`. The lobby opens: pick the difficulty, invite the players standing nearby and start.
{% endstep %}

{% step %}

### Walk in

The power is out, every player has a flashlight. The HUD shows the house, the room you stand in, the time left, your sanity, the objectives and your team.
{% endstep %}

{% step %}

### Find the ghost's room

It is the cold one, and the EMF reader reacts there.
{% endstep %}

{% step %}

### Collect evidence

Every ghost leaves exactly 3 of the 6 kinds. Mark what you found in the journal - every mark is shared with the team, and ghosts that no longer fit are ruled out.
{% endstep %}

{% step %}

### Name the ghost

Name the ghost in the journal and **photograph it** when it shows itself.
{% endstep %}

{% step %}

### Survive

The lower the team's sanity, the more the ghost does. Below a point it hunts. Hide in a wardrobe, or be caught.
{% endstep %}

{% step %}

### Get out

Go back to the ghost hunter and end the investigation. The report shows what the ghost really was, what the team found and what everybody is paid.
{% endstep %}
{% endstepper %}

| Key             | Action                                                                   |
| --------------- | ------------------------------------------------------------------------ |
| `E`             | Talk to the ghost hunter, use things in the house, end the investigation |
| `1` `2` `3` `4` | Thermometer, EMF reader, spirit box, camera                              |
| `G`             | Use the tool in hand - ask the spirit box a question, raise the camera   |
| `X`             | Put the tool away                                                        |
| `F`             | Flashlight                                                               |
| `J`             | Journal                                                                  |
| `B`             | Put the writing book down, or pick it up                                 |
| `K`             | Put the silhouette projector down, or pick it up                         |
| `H`             | Night vision while looking through the camera                            |
| `Y` / `N`       | Accept / decline a team invite                                           |
| `U`             | Start or stop watching the team after being caught                       |
| `F7`            | Hide or show the HUD card                                                |
| `DELETE`        | City mode: hold to drop the case on the way to the house                 |

Looking through the camera: `LMB` takes a photo, `RMB` lowers it, the mouse wheel zooms.

## Evidence & Tools

Every ghost leaves exactly **3 of these 6**. Two found pieces leave a couple of ghosts, the third one names it.

| Evidence                 | How the team finds it                                                                     |
| ------------------------ | ----------------------------------------------------------------------------------------- |
| **EMF level 5**          | The EMF reader near the ghost. Every ghost moves it to 2, 3 or 4 - only level 5 counts    |
| **Freezing temperature** | The thermometer in the ghost's room. The room cools down slowly, below 0° counts          |
| **Orbs on camera**       | Orbs float around the ghost, visible only through the camera. They come and go            |
| **Spirit box answers**   | Ask a question close to the ghost. A ghost that talks answers some of them                |
| **Ghost writing**        | Put the writing book down in the ghost's room and wait. It writes a word into it          |
| **Projector silhouette** | Put the silhouette projector down. The ghost walks through the laser dots as a silhouette |

Writing and the silhouette never come together - finding one rules out the other.

```lua
Config.Tools = {
	exclusive = true, -- true = every tool can only be held by one player at a time, so the team has to split them up

	thermometer = {
		ambient = 18.0, -- What a room far from the ghost reads, in celsius
		start = 10.0, -- What the ghost's room reads when the team first walks in
		cooltime = 90 -- Seconds the ghost's room takes to cool down to the ghost's mintemp
	},

	emf = {
		outside = 1,
		room = 2,
		near = {2, 4}, -- Levels the reader jumps between close to the ghost. Every ghost does this
		nearfive = 0.15, -- Chance an EMF 5 ghost pushes the reader to 5 while you stand close to it
		spikefive = 0.7 -- Chance an EMF 5 ghost hits 5 when something happens in its room
	},

	spiritbox = {
		range = 6.0, -- Metres from the ghost a question has to be asked from
		chance = 0.3, -- Chance a ghost that talks actually answers
		cooldown = 6
	},

	camera = {
		personal = true, -- true = every player has his own camera, even with exclusive on
		range = 12.0,
		nightvision = true,
		zoom = {enabled = true, max = 4.0, steps = 8}
	}
}
```

`Config.Temperature = "celsius"` or `"fahrenheit"` only changes what the thermometer shows.

### Spirit box

Every question the player can ask and the answers the ghost can give are in `Config.SpiritBox`, each with its own voice file. `{room}` in an answer is replaced by the name of the ghost's room.

### Writing book and projector

```lua
Config.Book = {
	enabled = true, -- false takes the book and the writing evidence out of the game
	delay = 60, -- Seconds the book has to lie there before the ghost can write in it
	texts = {"GET OUT", "LEAVE", "MINE", "HELP ME", "I SEE YOU", "DIE", "BEHIND YOU", "NOT ALONE"}
}

Config.Projector = {
	enabled = true, -- false takes the projector and the silhouette evidence out of the game
	range = 7.0, -- How far the dots reach, in metres
	points = 180, -- How many laser dots it projects
	color = {70, 255, 110},
	ghostcolor = {255, 40, 40}, -- The dots turn this colour while the ghost walks through them
	delay = 45,
	cooldown = 60
}
```

The orbs are in `Config.Orbs`, the flashlight in `Config.Flashlight`.

## Ghosts

10 ghosts are included. Every hunt picks one at random.

| Ghost           | Evidence                         | Behaviour                                                     |
| --------------- | -------------------------------- | ------------------------------------------------------------- |
| **Poltergeist** | EMF 5, Orbs, Writing             | Throws whatever it can reach, several things at once          |
| **Banshee**     | Freezing, Orbs, Silhouette       | Picks one victim and hunts nobody else                        |
| **Shade**       | EMF 5, Freezing, Writing         | Does nothing while two or more players are in its room        |
| **Wraith**      | EMF 5, Spirit box, Silhouette    | No footsteps when hunting, whispers a lot                     |
| **Demon**       | Freezing, Spirit box, Writing    | Hunts early and often, may not stop until it takes someone    |
| **Revenant**    | Orbs, Spirit box, Silhouette     | Slow until it sees you, then very fast                        |
| **Phantom**     | Freezing, Spirit box, Silhouette | Seeing it costs sanity, almost invisible when hunting         |
| **Mare**        | Freezing, Orbs, Writing          | Puts out the lights, blows the fuse, hunts sooner in the dark |
| **Yurei**       | EMF 5, Orbs, Silhouette          | Drains sanity fast, plays with the doors                      |
| **Changeling**  | EMF 5, Spirit box, Writing       | Always shows orbs it does not have, lies on the ghost board   |

### Adding your own ghost

Everything is in `configs/ghosts.lua`. Copy a ghost, give it a new name and change what it leaves and how it behaves:

```lua
["poltergeist"] = {
	enabled = true, -- false leaves it out entirely
	label = "Poltergeist",
	description = "Loud and restless. Throws whatever it can reach.",
	image = "img/ghosts/poltergeist.webp", -- Picture in the journal, inside html/
	lore = "It feeds on noise and chaos.",
	emf = true, -- EMF level 5
	mintemp = 4.0, -- Below 0 is the freezing evidence
	orbs = true,
	spiritbox = false,
	writing = true,
	projector = false,
	huntfear = 25, -- Average team sanity in % below which it can start hunting
	huntspeed = 1.0,
	eventmultiplier = 1.25, -- How often it does anything at all
	throwmultiplier = 3.5,
	targetslone = false,
	events = {burst = 2.0}, -- How much more often it picks a single event
	weight = 1.0 -- How likely it is to be picked
}
```

| Option                              | What it does                                                                         |
| ----------------------------------- | ------------------------------------------------------------------------------------ |
| `forced`                            | One evidence that is never hidden, whatever the difficulty                           |
| `fake`                              | One evidence the ghost does not have but shows anyway                                |
| `targetslone`                       | Goes after the player furthest from the rest of the team                             |
| `onlytarget`                        | Picks one victim on its first hunt and hunts nobody else                             |
| `groupshy`                          | No events and no hunts while two or more players are in its room                     |
| `silenthunt`                        | No footsteps while it hunts                                                          |
| `hiddenhunt`                        | Almost invisible while it hunts                                                      |
| `sighthunt`                         | Slow while it cannot see its target, fast once it can                                |
| `relentless`                        | Chance a hunt against a player with no sanity does not stop until somebody is caught |
| `huntcooldown`                      | Shorter or longer break between two hunts                                            |
| `drain`                             | How fast sanity drains while it is around                                            |
| `seenfear`                          | Extra sanity lost every time a player sees it                                        |
| `darkhunt`                          | Hunts sooner while the fuse is blown                                                 |
| `lightsout` / `lightsoutany`        | Puts out the lights more often, in its room or in the whole house                    |
| `ghostboardcost` / `ghostboardlies` | Cheaper questions on the ghost board, or wrong answers                               |

{% hint style="warning" %}
No two ghosts may leave the same 3 evidences, and every ghost should leave exactly 3. The server checks both when it starts and prints what is wrong into the console.
{% endhint %}

The ghost's body, how see-through it is, its glow and how it moves between rooms are in `Config.Ghost`. `models` takes any ped, one is picked at random every hunt.

## Sanity

Every player has his own sanity. It starts full and drains for as long as he is inside - faster in the ghost's room and when he is alone. Scares cost sanity to the players close enough to live through them. Standing next to a light that is on calms a player down.

The lower the team's average, the more the ghost does. Below the ghost's own `huntfear` it can start a hunt, and it goes after the players with the least sanity first.

```lua
Config.Fear = {
	start = 100.0,
	drain = 0.16, -- Lost every second just for being in the house
	ghostroom = 0.3, -- Extra per second in the ghost's room
	alone = 0.15, -- Extra per second with nobody else close
	alonedistance = 8.0,
	spiritbox = 3.0, -- Lost every time the ghost answers the spirit box
	scare = 2.0, -- Lost on every scare event the team lives through
	jumpscare = 5.0,
	radius = 10.0 -- Scares only cost sanity to players this close
}
```

## Ghost Events

The ghost does something every few seconds - from `slowest` at full sanity to `fastest` at none. `weight` is how likely each event is compared to the others, `0` turns one off.

| Event        | What happens                                                                                                   |
| ------------ | -------------------------------------------------------------------------------------------------------------- |
| `flicker`    | The lights flicker for everybody inside                                                                        |
| `slam`       | A door bangs shut                                                                                              |
| `creak`      | A door slowly swings open on its own                                                                           |
| `throw`      | Something near the ghost flies off a shelf - throwables from the creator and loose things already in the house |
| `burst`      | Several things fly one after another                                                                           |
| `knock`      | Three knocks, heard from where the ghost is                                                                    |
| `footsteps`  | Footsteps walk from the ghost towards one player                                                               |
| `whisper`    | One player hears a whisper right next to his ear                                                               |
| `lights`     | A lamp or candle goes out                                                                                      |
| `radio`      | A radio switches itself on                                                                                     |
| `tv`         | A TV switches itself on                                                                                        |
| `phone`      | A phone starts ringing                                                                                         |
| `manifest`   | The ghost shows itself in its room - the moment for the camera                                                 |
| `walk`       | The ghost walks out of its room and fades away                                                                 |
| `apparition` | One player sees it standing somewhere it should not be                                                         |
| `power`      | The ghost blows the fuse. Every lamp goes out until somebody turns the power back on at the fuse box           |
| `critters`   | The rats near the ghost scatter                                                                                |
| `rocking`    | A rocking chair starts rocking on its own                                                                      |
| `jumpscare`  | One player with low sanity gets a jumpscare                                                                    |

```lua
Config.Events = {
	slowest = 50, -- Seconds between events at full sanity
	fastest = 16, -- Seconds between events at no sanity left
	first = 40, -- Seconds after the first player walks in before the ghost does its first thing

	list = {
		flicker = {weight = 22, duration = 2500},
		throw = {weight = 30, force = 9.0, radius = 7.0, world = 0.6, maxsize = 1.2},
		jumpscare = {weight = 7, fear = 65, cooldown = 75}
		-- ...
	}
}
```

### Jumpscares

7 types, each with its own sound, timecycle, screen effect and camera: `face`, `behind`, `dark`, `rush`, `stepper`, `drop` and `side`. Every one ends with a sting - the camera snaps onto the ghost's face and zooms in. All of it is in `Config.Jumpscares` and `Config.JumpscareCinematic`.

### Hallucinations

Below `sanity` a player starts seeing and hearing things that are not there. Only he notices them: knocking behind him, footsteps, a whisper, the ghost at the edge of his view, the room swaying, his lights flickering - and **fake hunts** that look real and cannot catch him.

```lua
Config.Hallucinations = {
	enabled = true,
	sanity = 35,
	interval = {35, 80},
	hunt = {enabled = true, sanity = 20, chance = 0.2, duration = 12}
}
```

## Hunts

When the team's sanity is low enough the ghost goes after one of them. Lightning hits, the lights go mad, the exit doors lock, and after a few seconds the ghost appears and walks the house. Whoever it catches is out of the investigation.

* **Hide** in a wardrobe - a ghost cannot find a hidden player
* Flashlights flicker while the ghost is close, and its footsteps get louder
* Candles are blown out and lamps flicker when it walks past
* A caught player is knocked down in a short cinematic, put outside and can [spectate](#spectating)
* With `Config.Voice` on, a player talking close to the ghost becomes its target

```lua
Config.Hunt = {
	chance = 0.35, -- Chance every event tick that a hunt starts once sanity is below the ghost's huntfear
	duration = 22, -- Seconds a hunt lasts
	cooldown = 60, -- Seconds before the next one can start
	catchdistance = 1.3,
	lockexits = true, -- Doors marked "exit" in the creator lock for the whole hunt
	grace = 3, -- Seconds between the hunt starting and the ghost appearing
	pace = 1.4, -- 1.0 walks, 2.0 runs, 3.0 sprints
	caughtreward = 0.5, -- A caught player still gets this share of his reward
	kill = false, -- true = a caught player really dies and your framework's death takes over
	lockout = true, -- true = a caught player cannot get back in
	relentless = {enabled = true, sanity = 0, maxtime = 120}
}
```

### Barriers

For doorways with no real door. Mark the opening in the creator and nobody gets through it while the ghost hunts.

```lua
Config.Barriers = {
	enabled = true,
	onlyhunt = true, -- false = the barriers hold the team in for the whole investigation
	push = 0.55,
	notify = true
}
```

## Haunted Objects

Everything is placed in the [Location Creator](#location-creator) and set up in `configs/objects.lua`. Each object is spawned for the team only, for as long as the investigation runs.

| Object                                   | What it does                                                                                                                                         |
| ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Ghost board**                          | Ask a question and the planchette spells the answer for the whole team. Every question costs sanity. Leave without "Goodbye" and the board is cursed |
| **Tarot cards**                          | Draw cards until the deck is empty. Every card does something different, good or bad                                                                 |
| **Voodoo doll**                          | Every use pushes a random pin in and forces the ghost to react. The heart pin starts a hunt                                                          |
| **Music box**                            | Wind it up by hand with the mouse. The tune plays through the house and the ghost hunts when it ends                                                 |
| **Mirror**                               | Whisper "Bloody Mary" three times. The ghost writes on the mirror in blood and is angry for a while                                                  |
| **Old phone**                            | The ghost makes it ring. Pick it up and a voice whispers the name of the ghost's room                                                                |
| **Radio**                                | Plays and lures the ghost - it does things more often                                                                                                |
| **TV**                                   | Static on the screen. The ghost switches it on by itself. Works with TVs already in the map too                                                      |
| **Coffin**                               | A gamble: a clue or a jumpscare                                                                                                                      |
| **Cursed teddy**                         | Squeeze it and it laughs. Near the ghost, the ghost shows itself                                                                                     |
| **Old diary**                            | Reading it reveals one piece of the ghost's evidence                                                                                                 |
| **Fuse box**                             | The house's power. Too many lights on and the fuse blows by itself                                                                                   |
| **Rats**                                 | Scatter squeaking when a player or the ghost comes near                                                                                              |
| **Rocking chair**                        | Starts rocking on its own when the ghost is near                                                                                                     |
| **Wardrobe / hiding point**              | Climb in and watch the room through the gap in the doors                                                                                             |
| **Lamp / light / light switch / candle** | The team switches them on, the ghost switches them off. Bulbs can burst                                                                              |
| **Throwable**                            | Something small the ghost throws                                                                                                                     |
| **Apparition point**                     | A spot where the ghost is seen standing                                                                                                              |

Every object has `uses`, `cooldown`, `fear` and `distance`, and its own options below that.

### Tarot cards

```lua
Config.Tarot = {
	enabled = true,
	deck = 10, -- Cards in the deck
	cards = {
		tower = {weight = 20},
		wheel = {weight = 20, amount = 25.0}
		-- ...
	}
}
```

| Card                 | What it does                                               |
| -------------------- | ---------------------------------------------------------- |
| The Tower            | The ghost does something right away                        |
| The Wheel of Fortune | Burns green or red - the player gains or loses sanity      |
| The Fool             | Pretends to be another card. Nothing happens               |
| The Devil            | A jumpscare hits the player                                |
| Death                | A hunt starts and goes after this player                   |
| The Hermit           | The ghost is bound to its room and cannot hunt for a while |
| The Sun              | Sanity fully restored                                      |
| The Moon             | Sanity drops to zero                                       |
| The High Priestess   | Brings a caught teammate back, or spares the next one      |
| The Hanged Man       | The player is taken by the ghost                           |

The card art is in `html/img/tarot`. Who revives the player for The High Priestess is `Config.Ambulance`.

### Ghost board

14 questions are included: is it here, how old it is, is it close, how many of you are inside, does it know your name, what it wants, is it angry, when it will hunt, **where it is**, and "show yourself". Each has its own cost, and each can be changed, switched off or added in `configs/objects.lua`.

```lua
ghostboard = {
	questions = 8, -- How many questions the board answers before it burns out. "Goodbye" is free
	costgrow = 0.2, -- Every question already asked makes the next one cost 20 % more
	lowsanity = 20, -- A player below this sanity who asks makes the planchette fly off and the ghost hunt him
	cursehunt = true, -- true = leaving the board without "Goodbye" starts a hunt on that player
	silence = 0.2, -- Chance the ghost ignores a question
	annoy = 0.25 -- Chance the ghost gets annoyed after answering and does something around the board
}
```

### Lights

```lua
Config.Bulbs = {
	enabled = true,
	switch = 0.05, -- Chance a bulb bursts the moment a player switches it on
	ghost = 0.3, -- Chance the ghost bursts a bulb instead of only switching it off
	fear = 2.0
}
```

`fusebox.overload = 3` in `configs/objects.lua` - the fuse blows when more electric lights than this are on at once.

## The Journal

Opened with `J`. Every mark is shared with the whole team.

| Page              | What is on it                                                                                                                                                |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Evidence**      | Mark what the team found. Ghosts that do not fit are ruled out. Every ghost has its own page with its picture, evidence and behaviour. Pick your answer here |
| **What happened** | Everything the ghost did, with the time and the room                                                                                                         |
| **Objectives**    | The objectives and the bonus objectives with their rewards                                                                                                   |
| **Equipment**     | What every tool does                                                                                                                                         |
| **Haunted items** | What every object in the house does                                                                                                                          |
| **Photos**        | Every photo the team took, with the room and the time                                                                                                        |
| **Team**          | The players and their sanity                                                                                                                                 |

```lua
Config.Journal = {
	style = "paper", -- "paper" = an old notebook with handwriting and photos, "classic" = the dark panel
	photos = {
		enabled = true,
		resource = "screenshot-basic",
		size = 800,
		quality = 0.6,
		max = 12 -- Photos kept in the journal, the oldest go first
	}
}
```

## Difficulty

The leader picks one in the lobby. Every value is a multiplier on the normal settings.

```lua
Config.Difficulty = {
	enabled = true, -- false hides the choice and every hunt uses default
	default = "normal",
	levels = {
		{id = "easy", time = 1.25, drain = 0.7, events = 1.25, huntspeed = 0.9, huntduration = 0.85, huntfear = -5, evidence = 3, reward = 0.75},
		{id = "normal", time = 1.0, drain = 1.0, events = 1.0, huntspeed = 1.0, huntduration = 1.0, huntfear = 0, evidence = 3, reward = 1.0},
		{id = "nightmare", time = 0.8, drain = 1.5, events = 0.75, huntspeed = 1.15, huntduration = 1.2, huntfear = 10, evidence = 2, reward = 1.6}
	}
}
```

| Value                        | What it changes                                                      |
| ---------------------------- | -------------------------------------------------------------------- |
| `time`                       | The time limit                                                       |
| `drain`                      | How fast sanity drains                                               |
| `events`                     | The time between two things the ghost does                           |
| `huntspeed` / `huntduration` | How fast the ghost hunts and for how long                            |
| `huntfear`                   | How much sooner it starts hunting                                    |
| `evidence`                   | How many of its 3 evidences the ghost gives. The rest never shows up |
| `reward`                     | The money at the end                                                 |

Add as many levels as you like. Their names and descriptions are in `html/languages/en.json` under `difficulty`.

## Rewards & Bonus Objectives

```lua
Config.Rewards = {
	account = "money", -- "money" = cash, "bank", or any other account your framework has
	base = 500, -- For ending the investigation at all
	correct = 750, -- For naming the right ghost
	photo = 400, -- For a photo of the ghost
	fast = 300, -- For ending within fasttime minutes
	fasttime = 8,
	wrongpenalty = 0.5, -- The base reward is multiplied by this when the team named the wrong ghost

	items = {
		-- {name = "pumpkin_candy", count = 1, chance = 1.0}
	}
}
```

Every run `count` bonus objectives are picked at random and shown in the HUD. Objectives that cannot be done in this house are never picked.

```lua
Config.Bonus = {
	enabled = true,
	count = 5,
	list = {
		evidence = {weight = 10, reward = 400}, -- Mark every piece of evidence correctly
		board = {weight = 8, reward = 200}, -- Get an answer from the ghost board
		hide = {weight = 5, reward = 250}, -- Hide in a wardrobe while the ghost is hunting
		photo_mirror = {weight = 6, reward = 250} -- Photograph the writing on the mirror
		-- ...
	}
}
```

22 objectives are included: using every haunted object, hiding during a hunt, surviving a hunt with the whole team, naming the right ghost with nobody caught or with high sanity, and photo objectives - the rocking chair while it rocks, the music box while it plays, the ghost board while it moves and the writing on the mirror.

The payout itself is `GiveRewardRTX` in `server/other.lua` - rewrite it for your own rewards.

## House Mode & City Mode

```lua
Config.Hunter = {
	mode = "house", -- "house" or "city"
	model = "s_m_m_scientist_01",

	city = {
		points = {
			vector4(308.14, -906.18, 28.36, 67.0)
		},
		arrivedistance = 12.0,
		traveltime = 15, -- Minutes the team has to reach the house. 0 for no limit
		waypoint = true,
		handin = 60 -- Minutes a finished report can still be handed in for its reward
	}
}
```

| Mode      | How it works                                                                                                                                                                                                                                                                                                               |
| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `"house"` | A ghost hunter stands outside every haunted house. The team is put together there, hunts and ends the investigation with him                                                                                                                                                                                               |
| `"city"`  | The ghost hunters stand in the city. A player picks a house from the **case board** with its photo and story, puts a team together and takes the case. Everybody gets a waypoint, the hunt starts on its own once the whole team is at the house, and the reward is paid when the report is brought back to a ghost hunter |

Blips for the houses and the ghost hunters are in the same section.

## Teams, Time & Instances

```lua
Config.Team = {
	maxplayers = 4, -- Players in one team, the leader included. 1 lets people hunt alone
	minplayers = 1,
	invitedistance = 15.0,
	invitetime = 30
}

Config.Session = {
	timelimit = 20, -- Minutes a team has before the ghost wins by default
	cooldown = 10, -- Minutes a player waits before he can start or join another hunt. 0 for none
	instanced = true,
	blackout = true, -- The power is out while the team is inside
	photorequired = false, -- true = the investigation cannot be ended until the ghost has been photographed

	leave = {enabled = true, distance = 120.0, grace = 10} -- A player who goes too far from the house drops out
}
```

| `instanced` |                                                                                                                                       |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `true`      | Every team hunts in its own routing bucket. Any number of teams can hunt the same house at once and nobody else sees them             |
| `false`     | One team per house at a time, and everybody else sees them in there. Players close to the house see the ghost too, see `Config.Watch` |

`Config.Hours` limits when hunts can start, on the game clock or the real one. Every house can have its own hours in the creator.

## Who Can Play

Off by default, so everybody can.

```lua
Config.Access = {
	enabled = false,

	ace = {enabled = false, permission = "ghosthunting.play"},
	jobs = {enabled = false, list = {"paranormal", "police"}},
	groups = {enabled = false, list = {"vip", "admin", "superadmin"}},
	identifiers = {enabled = false, list = {}},

	item = {enabled = false, name = "ghost_ticket"} -- An item every player has to carry. It is not taken away
}
```

A player gets in if he matches **any** of the enabled parts. The whole check is `CanPlayerStartHuntRTX` in `server/other.lua`.

## Spectating

A caught player watches his team while he waits outside. Left and right arrow switch between teammates, `V` switches between first and third person, Backspace stops.

```lua
Config.Spectate = {
	enabled = true,
	auto = true, -- true starts watching right after he is put outside
	firstperson = false
}
```

## Leaderboard

Opened from the lobby with the trophy button. Every finished hunt is counted per player: **solved, hunts, fastest solve and money earned**.

```lua
Config.Leaderboard = {
	enabled = true,
	top = 10
}

Config.Identifier = "framework" -- "framework" = every character counts on its own. "license", "discord", "steam" or "fivem" = one for all characters
```

## Location Creator

```
/ghostcreator
```

Opens the list of every haunted house. From there you can make a new one, edit one, teleport to it or delete it. Saving makes a house live for everybody - **no restart**.

### The house

| Part                  | What it is                                                                                                                |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| **Name** and **blip** | What the players see                                                                                                      |
| **Ghost hunter**      | Outside, next to the front door. The team gathers here and comes back here to finish                                      |
| **House outline**     | The whole house from above, roof included. Inside it the power is out and the ghost can get you. Outside the team is safe |
| **IPL interior**      | For houses with no real door to the street. Place the entrance and the inside point, the team teleports in and out        |
| **Look inside**       | How dark it is inside. Standard, Dim, Dark, Pitch black, Cold, Faded, or your own from `Config.Looks`                     |
| **Hunting hours**     | Follow the config, any time, or its own hours                                                                             |
| **About the house**   | Its story and a photo for the case board                                                                                  |

### Rooms

At least two rooms, every room with at least one ghost spot.

* **Draw a room** - click the corners of the floor, then set the floor and the ceiling
* **From interior** - take the rooms straight from the interior by their room ID, nothing to draw. Several can be **merged** into one room
* **Add spots** - the places in that room the ghost can live on

### Doors and barriers

Aim at a door and click.

| Door       |                                            |
| ---------- | ------------------------------------------ |
| **Exit**   | Locks while the ghost hunts                |
| **Slam**   | The ghost bangs it shut and swings it open |
| **Locked** | Stays shut for the whole investigation     |

**Barriers** are for openings without a door - two corners on the floor and nobody gets through while the ghost hunts.

### Objects

Click an object and it shows up in front of you with a **gizmo**. The arrow keys switch the model where there is a choice. Lamps, candles and light switches have a live **light editor** - brightness, reach, colour and a spot beam, shown as you set them.

### Free camera

Press `C` in any placing mode to fly the camera and aim from it.

```lua
Config.Creator = {
	raydistance = 25.0, -- How far away the laser can place a point
	defaultheight = 3.2, -- Height of a new room
	freecam = {enabled = true, key = 26, label = "C", speed = 2.0, maxdistance = 80.0},
	photo = {enabled = true, resource = "screenshot-basic", size = 960, quality = 0.75}
}

Config.Limits = {
	objects = 150,
	rooms = 32,
	spots = 12, -- Ghost spots in one room
	doors = 40,
	barriers = 20,
	points = 48 -- Corners of one room or of the house outline
}
```

{% hint style="info" %}
A photo of a house taken in the creator is saved into `html/img/locations` and shows up after the resource is restarted.
{% endhint %}

Houses can be written by hand too, in `configs/locations.lua`. Most servers never open it.

### Two styles

| Value       | Look                                                                                 |
| ----------- | ------------------------------------------------------------------------------------ |
| `"paper"`   | Old case files, a paper journal with handwriting and photos, a report on a clipboard |
| `"classic"` | Clean dark panels, like the HUD                                                      |

`Config.Style.menus` and `Config.Journal.style` are set separately, so any mix works. The HUD, the tools and the creator always stay dark.

### Prompts in the house

```lua
Config.WorldPrompts = {
	enabled = true, -- Prompts drawn in 3D over the object itself
	hint = true, -- A small dot over every usable object nearby, so the team can find them in the dark
	hintdistance = 6.0,
	walls = true -- Nothing shows and nothing can be used through walls or closed doors
}
```

### Your own HUD

While a player is in an investigation, the rest of your server's interface steps aside. Most HUDs need one line in `hide` and one in `show`:

```lua
Config.OtherHud = {
	enabled = true,
	radar = true, -- true hides the minimap during the investigation
	hide = {
		-- {event = "yourhud:client:toggle", args = {false}},
		-- {export = "yourhud", func = "HideHud"}
	},
	show = {
		-- {event = "yourhud:client:toggle", args = {true}},
		-- {export = "yourhud", func = "ShowHud"}
	}
}
```

Notifications are `Notify()` in `client/other.lua`, where your own notification system goes.

### Keys

```lua
Config.Keys = {
	interact = 38,
	interactlabel = "E",

	thermometer = "1",
	emf = "2",
	spiritbox = "3",
	camera = "4",
	holster = "X",
	use = "G",
	camerafilter = "H",
	flashlight = "F",
	journal = "J",
	book = "B",
	projector = "K",
	accept = "Y",
	decline = "N",
	spectate = "U",
	dropcase = "DELETE",
	hud = "F7"
}
```

{% hint style="info" %}
Everything a player presses during a hunt is a key mapping. Every player can rebind it in **Settings > Key Bindings > FiveM**.
{% endhint %}

## Sounds

Every sound the resource makes is in `Config.Sounds`. Put a file into `html/sounds` and write its name there.

```lua
Config.Sounds = {
	jumpscare = {file = "jumpscare", volume = 1.0},
	whisper = {file = "whisper", volume = 1.0},
	hunt = {file = "hunt", volume = 1.0}
	-- ...
}

Config.Ambient = {
	enabled = true, -- Music inside every haunted house
	file = "sounds/ambient.mp3",
	volume = 0.16,
	huntvolume = 0.05, -- The music ducks to this while the ghost hunts
	mutegta = true -- Silences the city outside while inside the house
}

Config.SoundDistance = {
	near = 1.5,
	curve = 2.0,
	walls = true, -- A sound behind a wall or a closed door is quieter and muffled
	wallvolume = 0.45,
	stereo = 0.8 -- How far left or right a sound can pan
}
```

{% hint style="info" %}
A sound left as `""` or a file that is missing is made by the interface itself, so everything works without a single file.
{% endhint %}

## Storage

```lua
Config.Storage = {
	mode = "database",
	resource = "oxmysql"
}
```

| Mode         | Where houses and the leaderboard live                                                                              |
| ------------ | ------------------------------------------------------------------------------------------------------------------ |
| `"database"` | The tables `rtx_ghost_locations` and `rtx_ghost_stats`, created on their own. Houses survive updating the resource |
| `"file"`     | `data/locations.json` and `data/stats.json` inside the resource. Keep a copy when you update                       |

If `"database"` is set but `oxmysql` is not running, the files are used until it is. On the first start with an empty database, everything already in the files is copied over on its own. Another database resource is a few lines in `DatabaseQueryRTX` in `server/other.lua`.

## Commands

| Command         | Who       | What it does                                    |
| --------------- | --------- | ----------------------------------------------- |
| `/ghostleave`   | Everybody | Walk out of a running hunt. The team carries on |
| `/ghostcreator` | Admins    | The location creator                            |

```lua
Config.Commands = {
	creator = "ghostcreator",
	leave = "ghostleave",
}
```

Rename any of them, or set it to `""` and it is never registered.

## Permissions

```lua
Config.CreatorPermissions = {
	ace = {enabled = true, permission = "ghostcreator.use"},
	groups = {enabled = false, list = {"admin", "superadmin", "god"}},
	job = {enabled = false, name = "builder"},
	identifiers = {enabled = true, list = {}}
}
```

A player can use the creator, scene mode and the storage command if **any** enabled part says yes:

* he has the ACE `ghostcreator.use`
* his ESX group / QBCore permission is in `groups`
* he has the builder job
* one of his identifiers is in `identifiers`

## Language

Every line of text is open source: notifications in the `language` folder, the whole interface in `html/languages`. 18 languages are included:

English, German, Spanish, French, Czech, Polish, Portuguese, Italian, Russian, Turkish, Korean, Dutch, Chinese, Romanian, Hungarian, Thai, Japanese, Arabic

```lua
Config.Language = "German"
```

Anything missing in a language falls back to English.

## Open-Source Files

This product is protected by the Escrow System. You can still configure almost everything:

| File                    | What is in it                                                                                   |
| ----------------------- | ----------------------------------------------------------------------------------------------- |
| `config.lua`            | Everything configurable, fully commented                                                        |
| `configs/ghosts.lua`    | Every ghost type, its evidence and its behaviour                                                |
| `configs/objects.lua`   | Everything the creator can place, with its models and what it does                              |
| `configs/locations.lua` | Houses written by hand (optional)                                                               |
| `language/*.lua`        | Notification texts                                                                              |
| `html/languages/*.json` | Interface texts                                                                                 |
| `client/other.lua`      | Notifications, prompts, death check, hiding your HUD, voice check, revive, hooks                |
| `server/other.lua`      | Money, items, jobs, groups, access check, creator check, rewards, database, Discord logs, hooks |
| `html`                  | The interface                                                                                   |

### Discord logs

Switched on in `server/other.lua`, in `LogsRTX`. Started investigations, caught players and finished investigations with the ghost, the answer, the time and the reward. The webhook lives there too - never put it in `config.lua`, that file is sent to every player.

### Death and revive

How a dead or downed player is detected is `IsPlayerDownRTX()` in `client/other.lua` and `Config.Death`, open for your own ambulance script. A player who dies in the house any other way counts as caught.

## Exports & Events

### Client exports

```lua
exports.rtx_ghost:IsHunting() -- true while the player is in an investigation
exports.rtx_ghost:IsCreatorOpen()
exports.rtx_ghost:LeaveInvestigation() -- leaves the lobby or the investigation
exports.rtx_ghost:ShowNotify(text, title, type)
```

### Server exports

```lua
exports.rtx_ghost:IsPlayerHunting(source)
exports.rtx_ghost:GetLocations() -- every haunted house
exports.rtx_ghost:GetInvestigation(source) -- {location, members, alive, inside, hunting, difficulty} or nil
exports.rtx_ghost:KickFromInvestigation(source) -- takes a player out of his lobby or investigation
exports.rtx_ghost:EndInvestigation(source) -- ends the investigation of that player's team, counted as lost
```

### Server events

```lua
AddEventHandler("rtx_ghost:server:investigationStarted", function(source, location) end)
AddEventHandler("rtx_ghost:server:caught", function(source) end)
AddEventHandler("rtx_ghost:server:investigationFinished", function(source, result) end)
AddEventHandler("rtx_ghost:server:teleport", function(source, kind, coords) end) -- IPL houses, for your anticheat
```

`result` holds `reason`, `location`, `locationid`, `ghost`, `ghostid`, `guess`, `guessid`, `correct`, `photo`, `alive`, `minutes`, `reward`, `breakdown` and `bonus`.

### Client events

```lua
AddEventHandler("rtx_ghost:client:investigationStarted", function(location) end)
AddEventHandler("rtx_ghost:client:investigationEnded", function(result) end)
AddEventHandler("rtx_ghost:client:hunt", function(started) end) -- true when the ghost starts hunting, false when it stops
AddEventHandler("rtx_ghost:client:caught", function() end)
AddEventHandler("rtx_ghost:client:hiding", function(hidden) end)
AddEventHandler("rtx_ghost:client:house", function(inside) end) -- walking into and out of the house
AddEventHandler("rtx_ghost:client:otherHud", function(hidden) end)
AddEventHandler("rtx_ghost:client:teleport", function(when, coords) end) -- "before" and "after"
```

## Troubleshooting

<details>

<summary>The tools or the haunted objects are invisible</summary>

The `stream` folder is missing or was renamed. Put it back and restart the server - streamed models are only picked up by players who connect after the restart.

</details>

<details>

<summary>The creator says I am not allowed</summary>

Check the ACE in `server.cfg` and `Config.CreatorPermissions`. Any one enabled part is enough.

</details>

<details>

<summary>A house cannot be saved</summary>

A house needs a ghost hunter, a house outline (or an IPL interior) and at least two rooms, every room with at least one ghost spot. The creator shows what is still missing.

</details>

<details>

<summary>The houses are gone after an update</summary>

File storage keeps the houses inside the resource folder. Use `Config.Storage.mode = "database"`, or keep `data/locations.json` when you replace the folder. `/ghoststorage backup` writes everything into one file.

</details>

<details>

<summary>There is no Photos page in the journal</summary>

Photos need `screenshot-basic` running. Without it, or with `Config.Journal.photos.enabled = false`, the page is left out.

</details>

<details>

<summary>The house stays too bright with the power out</summary>

Some interiors have lights of their own. Pick a darker look for that house in the creator, under **Look inside**.

</details>

<details>

<summary>Nobody is paid on standalone</summary>

Standalone has no money system. Fill in `AddMoneyRTX` in `server/other.lua`.

</details>

<details>

<summary>My HUD stays on screen during an investigation</summary>

Add its hide and show event or export to `Config.OtherHud`.

</details>

<details>

<summary>A dead player is not counted as caught</summary>

Your ambulance script uses a death state the script does not know yet. Add its state bag to `Config.Death.statebags`, or its check to `IsPlayerDownRTX()` in `client/other.lua`.

</details>

<details>

<summary>My anticheat flags the teleport into an IPL house</summary>

Every teleport runs through the server first. Allow it in `OnTeleportRTX` in `server/other.lua` and in `BeforeTeleportRTX` / `AfterTeleportRTX` in `client/other.lua`.

</details>

<details>

<summary>The ghost is a wrong or missing model</summary>

`Config.Ghost.models` takes any ped model that exists on your server. Check the name, and that an addon ped is started before `rtx_ghost`.

</details>

## Support

If you need help with installation, configuration or have any questions regarding this resource, feel free to contact us on our Discord server:

[Join our Discord](https://discord.gg/rtxdev)
