Selection Screen Locations
A location is one place on the map, dressed with its own weather, time, grade and music, holding a camera for every character slot. Players see one location at a time and change it with J.
Internally a location is an entry in Config.SpawnPosition. That table is built from three sources.
The three sources
| Source | Where | Ships with | How you add one |
|---|---|---|---|
Config.SpawnPosition | config.lua | 11 | Edit the table by hand |
ConfigScenes.List | config_scenes.lua | 2 | Paste a scene from the Scene Creator's Export tab |
| The database | vorp_character_scenes | — | Save a scene in the Scene Creator and switch it LIVE |
13 locations ship in files, plus however many database scenes are LIVE. The eleven in config.lua are Vanhorn, Vanhorn 2, Saloon of Armadillo, Cotorra Springs, Donner Falls, The HeartLands 1, The HeartLands 2, Swamps 1, Colter, Manzanita Post and Armadillo Cemetery — each with five character marks.
The two in config_scenes.lua are worked examples of Scene Creator output. They carry 2 marks and 1 mark, which makes them the quickest way to see what happens when a location has fewer marks than the player has characters.
config_scenes.lua appends its entries to Config.SpawnPosition at load, so a pasted scene behaves exactly like one written into config.lua. The merge runs on both the client and the server, and reports itself:
[vorp_character:scenes] added 2 scene(s) from config_scenes.lua, 13 totalconfig_scenes.lua has to load straight after config.lua
The merge needs Config.SpawnPosition to exist already. The shared_scripts order in fxmanifest.lua puts it second for that reason. Move it and you get config.lua has not loaded yet; check the shared_scripts order in fxmanifest.lua and none of the pasted scenes appear.
The merge also validates. An entry without options.mainCam, an entry with no positions, or a position missing spawn, camera, scenario.mp_male or scenario.mp_female is skipped and named in the console rather than breaking the screen:
[vorp_character:scenes] entry 3 has no options.mainCam, skipped
[vorp_character:scenes] entry 4 position 2 is missing spawn or camera, skippedSet ConfigScenes.Enabled = false to ignore the whole file without deleting anything from it.
The shape of a location
{
name = "Manzanita Post",
options = {
timecycle = { name = "teaser_trainShot", strength = 1.00 },
music = "REHR_START",
weather = { type = "sunny", transition = 10, snow = false },
time = { hour = 12, transition = 10 },
playerpos = vector3(2967.38, 488.73, 47.21),
mainCam = { x = 2967.38, y = 488.73, z = 47.21,
rotx = 0.0, roty = 0.0, rotz = 105.0, fov = 60.0 },
},
positions = {
{
spawn = vector4(2959.76, 483.66, 47.39, 282.33),
camera = { x = 2963.62, y = 484.00, z = 47.87,
rotx = 0.0, roty = 0.0, rotz = 90.0, fov = 60.0 },
scenario = {
mp_male = { "MP_LOBBY_SCENARIO_02", "WORLD_HUMAN_SMOKE_CARRYING" },
mp_female = { "MP_LOBBY_SCENARIO_02", "WORLD_HUMAN_SMOKE_CARRYING" },
},
},
},
}options — the whole scene
| Field | What it does |
|---|---|
name | Optional. The label in the location list. Without it the list reads Location 1, Location 2 and so on |
timecycle.name | Screen grade applied with SetTimecycleModifier. "" for none |
timecycle.strength | How hard the grade is pushed. 1.00 is full |
music | An RDR3 music event, started when the screen opens and stopped with MC_MUSIC_STOP. "" for silence |
weather.type | Weather set through weathersync for this player only |
weather.transition | Seconds the weather takes to arrive |
weather.snow | Ground snow on or off |
time.hour | Hour of day, 0 to 23 |
time.transition | Seconds the time change takes |
playerpos | Where the real player ped is parked while the screen is up |
mainCam | The opening wide shot, before the camera moves to a character |
playerpos is not decoration. The player's own ped is teleported there, frozen, made invincible and hidden, and the screen waits for collision to finish loading around it before anything is staged. Put it inside the scene, near the marks. A playerpos far from the cameras means the ground the characters stand on may not be loaded when they are placed.
mainCam is a position and a set of Euler angles, not a look-at. rotx is pitch, rotz is yaw, roty stays 0.0. The camera interpolates from here to the highlighted character's own camera over ConfigSelector.Scene.interpDuration, 1200 ms by default.
Weather and time can be the player's choice instead
Priority runs player Settings, then the location's options, then the defaults. Setting ConfigSelector.Environment.allowPlayerOverride = false makes every location always use its own weather and time. See Configuration.
positions — one entry per character slot
| Field | What it does |
|---|---|
spawn | A vector4: where the character stands, plus its heading |
camera | The close-up camera for that character, same shape as mainCam |
scenario.mp_male | Scenarios this mark offers a male character |
scenario.mp_female | Scenarios this mark offers a female character |
Both sex keys are required. One scenario is chosen from the matching list when the character is staged, so a list of four gives the mark four possible idles rather than one.
What players can then cycle with E depends on ConfigSelector.Animations.source: "slot" keeps them to the mark's own scenarios, "global" ignores them, and "merged" — the default — offers the mark's scenarios first and the global list after. That, and perLocation for restricting poses to particular locations, is on Poses.
One mark per character slot
positions is indexed by character slot, so slot 1 stands at positions[1]. Give every location as many marks as the highest number of characters a player can have, which is why all eleven shipped locations carry five.
When a location has fewer marks than the player has characters, the screen does not fail. It fills the gap from the last real mark, stepping 2 m sideways per missing mark along that mark's own heading, copying its camera by the same offset and reusing its scenario lists. Each generated mark is flagged derived internally, and the console says what happened:
[vorp_character] scene 12 has 2 character position(s) but 4 are needed. Spacing the rest out
automatically - add them properly in /scenecreator, or in the scene's `positions` table.Treat that line as a to-do. The spacing keeps the screen usable, but it is blind: it has no idea whether 2 m to the side is a porch, a hitching rail or the middle of a river, and it hands the copied camera the same offset, so the framing drifts with it.
A location with no positions at all cannot be staged and says so:
[vorp_character] scene 12 has no character positions at all; it cannot be stagedAdding marks is cheaper than raising the character limit
Raising the maximum characters in vorp_core without adding marks to all 13 locations means the last slots are auto-spaced at every one of them. Build the marks first.
How the rotation works
The server decides which location a player gets. It draws an index, sends it to the client with the character list, and every character on screen is staged at that one location.
Which numbers the draw runs across depends on where the locations live. File locations exist on both the client and the server, because config.lua and config_scenes.lua are shared scripts. LIVE database scenes only ever exist on the client, which rebuilds its own Config.SpawnPosition from the list the server pushes. So the server counts the LIVE scenes separately and adds that count to the file total before drawing.
How often the draw happens follows from the same split. With nothing but file locations in the rotation, server/server.lua draws its index once, when the resource starts, and reuses it for every screen opened after that — which is what the comment above Config.SpawnPosition means by locations being random each restart. As soon as at least one LIVE database scene is in the rotation, the server draws again every time a player opens the screen, across the file locations and the LIVE scenes together.
One LIVE scene is enough to make the rotation per-player
If every player on your server keeps landing in the same town until the next restart, that is the behaviour above, not a broken config. Save one scene in the Scene Creator and switch it LIVE, and the draw becomes fresh on every open. Players can also move between locations themselves with J.
| Setting | File | Default | Does |
|---|---|---|---|
ConfigScenes.Enabled | config_scenes.lua | true | Use the scenes in that file |
ConfigCreator.ApplyToSelector | config_scenecreator.lua | true | LIVE database scenes join the rotation |
ConfigCreator.ReplaceConfigScenes | config_scenecreator.lua | false | LIVE scenes replace the file locations instead of being added to them |
With ApplyToSelector = false, a scene saved in the editor changes nothing for players until it is exported to config_scenes.lua and the resource restarts. With it on, switching a scene LIVE reaches players immediately — the server pushes the list and the client applies it, with no restart.
ReplaceConfigScenes cannot strand the selector
It defaults to false, it does nothing unless ApplyToSelector is also on, and it is ignored whenever no usable LIVE scene exists. Asking for replacement with nothing to replace the files with logs replace was asked for but no created scene is usable, keeping config.lua scenes and keeps the file locations. You cannot end up with an empty rotation by setting this flag.
A mismatch between the server's index and the client's list is caught rather than crashed:
[vorp_character] location 14 does not exist, falling back to 1A scene that is both LIVE and pasted into config_scenes.lua counts twice
The two sources are counted independently, so the same scene occupies two slots in the rotation and comes up twice as often as everything else. After exporting a scene into config_scenes.lua, switch the database copy off in the Scene Creator — or keep it in the database only. Pick one home per scene. See Scene Creator.
Players move between locations themselves with J, which steps to the next index and wraps around. It needs at least two locations in the rotation, and ConfigSelector.Scene.allowLocationCycle set to true, which is the default. Changing location fades out, tears the scene down and rebuilds it, and the highlighted character is clamped to the number of marks the new location has. ConfigSelector.Scene.showLocationBadge adds a small Location N chip in the corner and is false by default; it does not affect cycling.
spawn.z is origin level, not foot level
This is the single most common cause of hovering or sunken characters in a hand-written location.
spawn.z is the ped's origin, which sits about 0.9 m above the feet. A coordinate read from a tool that reports the ground or the sole of the boot is roughly 0.9 m lower than what belongs in spawn.
The native used to place the ped matters as much:
| Native | Effect on a ped |
|---|---|
SetEntityCoords | Lifts the ped by the origin offset, about 0.9 m |
SetEntityCoordsNoOffset | Puts the origin exactly where you asked |
The resource places every selector and Scene Creator ped with SetEntityCoordsNoOffset, so the Z in spawn is used as written. Mixing the two conventions is what produces the two classic symptoms:
- Floating about 0.9 m up — a foot-level Z was placed with an offsetting native, or an origin-level Z was written as if it were foot level.
- Sunk to the knees — a ground Z was pasted straight into
spawn.
Let the Scene Creator write the Z
Placement snaps to ground and keeps a mark at least 0.35 m above it, so an exported or LIVE scene already carries a correct origin-level Z. Hand-edited entries in config.lua are where this goes wrong. If you are typing coordinates, place a mark in the editor nearby and copy its Z.
Two more things that follow from the same offset:
Moving a ped cancels its current task. Place a character, then start its pose — never the other way round. A watchdog re-checks every staged ped four times a second and, if one has walked off its mark or dropped out of its pose, puts it back with SetEntityCoordsNoOffset and starts the pose again.
Raw animation clips carry their own authored height. Scenarios are grounded by the engine and cannot float; a raw clip brings the height of the set it was authored on with it. Named clips can be corrected a few centimetres at a time in ConfigSelector.Partner.clipOffsets, which ships with two entries, KIT_EMOTE_GREET_FANCY_BOW_1 at 0.128 and MP_LOBBY_SCENARIO_06 at 0.116. The difference between the three kinds of pose is explained on Emote library.
Removing a location
Delete its entry from Config.SpawnPosition or ConfigScenes.List, or switch the database scene off in the Scene Creator. Switching off is reversible and immediate; deleting a pasted block is not. The indexes of everything after it shift down by one, which matters if you have used perLocation in animations.lua to pin poses to particular location numbers — check those after any deletion.
Related pages
- Scene Creator — building locations in game instead of by hand
- Configuration — the selection screen settings referenced here
- Poses — what players cycle with E, and
perLocation - Database — the
vorp_character_scenestable - Troubleshooting — hovering characters, empty rotations, missing scenes
- VORP framework — where character limits and cores are set
Still stuck? Ask in Discord.