Skip to content

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 ​

SourceWhereShips withHow you add one
Config.SpawnPositionconfig.lua11Edit the table by hand
ConfigScenes.Listconfig_scenes.lua2Paste a scene from the Scene Creator's Export tab
The databasevorp_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:

text
[vorp_character:scenes] added 2 scene(s) from config_scenes.lua, 13 total

config_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:

text
[vorp_character:scenes] entry 3 has no options.mainCam, skipped
[vorp_character:scenes] entry 4 position 2 is missing spawn or camera, skipped

Set ConfigScenes.Enabled = false to ignore the whole file without deleting anything from it.

The shape of a location ​

lua
{
    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 ​

FieldWhat it does
nameOptional. The label in the location list. Without it the list reads Location 1, Location 2 and so on
timecycle.nameScreen grade applied with SetTimecycleModifier. "" for none
timecycle.strengthHow hard the grade is pushed. 1.00 is full
musicAn RDR3 music event, started when the screen opens and stopped with MC_MUSIC_STOP. "" for silence
weather.typeWeather set through weathersync for this player only
weather.transitionSeconds the weather takes to arrive
weather.snowGround snow on or off
time.hourHour of day, 0 to 23
time.transitionSeconds the time change takes
playerposWhere the real player ped is parked while the screen is up
mainCamThe 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 ​

FieldWhat it does
spawnA vector4: where the character stands, plus its heading
cameraThe close-up camera for that character, same shape as mainCam
scenario.mp_maleScenarios this mark offers a male character
scenario.mp_femaleScenarios 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:

text
[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:

text
[vorp_character] scene 12 has no character positions at all; it cannot be staged

Adding 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.

SettingFileDefaultDoes
ConfigScenes.Enabledconfig_scenes.luatrueUse the scenes in that file
ConfigCreator.ApplyToSelectorconfig_scenecreator.luatrueLIVE database scenes join the rotation
ConfigCreator.ReplaceConfigScenesconfig_scenecreator.luafalseLIVE 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:

text
[vorp_character] location 14 does not exist, falling back to 1

A 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:

NativeEffect on a ped
SetEntityCoordsLifts the ped by the origin offset, about 0.9 m
SetEntityCoordsNoOffsetPuts 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.

  • 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_scenes table
  • Troubleshooting — hovering characters, empty rotations, missing scenes
  • VORP framework — where character limits and cores are set

Still stuck? Ask in Discord.

Documentation for RedMorrow. Scripts are licensed per server — redistribution is not permitted.