Skip to content

Race

The race the player is in.

OnTrack

bool Race::OnTrack()

Whether the player is on a track (a map with a race), as opposed to the menus.

Example
timerWindow.visible = Race::OnTrack() && ShowTimer;

IsActive

bool Race::IsActive()

Whether a race is running. It stays on through checkpoint respawns. It's off in the menus, after the finish, and for a moment during a restart.

Example
if (Race::OnTrack() && Race::IsActive())
    seconds += dt;

Restarts

int Race::Restarts()

Restarts from the beginning of the track since the game started: Backspace, or R before the first checkpoint. Checkpoint respawns and falls don't count. It comes from the game's own counter, so rebinding keys changes nothing.

Example
// Count new restarts
int now = Race::Restarts();
if (now > seenRestarts)
    restarts += now - seenRestarts;
seenRestarts = now;

Respawns

int Race::Respawns()

Respawns at a checkpoint since the game started: R once a checkpoint has been cleared. Falls don't count (see Falls), and neither does R before the first checkpoint (that's a restart). It comes from the game's own fault counter, so rebinding keys changes nothing. Read CurrentCheckpoint() in the same frame to know which one.

Example
// Count R respawns at each checkpoint
int now = Race::Respawns();
if (now > seenRespawns)
    respawnsAt[Race::CurrentCheckpoint() + 1] += now - seenRespawns;
seenRespawns = now;

Falls

int Race::Falls()

Falls into a kill zone since the game started. After a checkpoint the ball respawns there; before the first one it goes back to the start, and that isn't counted as a restart either.

Example
int now = Race::Falls();
if (now > seenFalls)
    Log::Info("fell " + (now - seenFalls) + " time(s)");
seenFalls = now;

CheckpointCount

int Race::CheckpointCount()

How many checkpoints (strips and discs) the track on screen has; 0 off a track. Many of the game's own tracks have none: there R always restarts from the beginning.

Example
Log::Info(Race::TrackName() + " has " + Race::CheckpointCount() + " checkpoints");

CheckpointPosition

bool Race::CheckpointPosition(int, double &out, double &out, double &out)

Where a checkpoint is (0 to CheckpointCount - 1). They are ordered by position, so the same checkpoint has the same index and position every time the track is played: use the position to recognise one across sessions.

Example
double x, y, z;
if (Race::CheckpointPosition(0, x, y, z))
    Log::Info("checkpoint 0 at " + int(x) + ", " + int(y) + ", " + int(z));

CurrentCheckpoint

int Race::CurrentCheckpoint()

The checkpoint a respawn would go to (the last one touched), or -1 before any this run. A restart from the beginning sets it back to -1.

Example
int cp = Race::CurrentCheckpoint();
cpText.text = cp < 0 ? "start" : "checkpoint " + (cp + 1);

RunId

int Race::RunId()

The run the player is on: a new number for every new run (a restart), the same through checkpoint respawns; -1 off a track. The ball also gets a new one when a race starts after the pre-race screen, so count while IsActive().

Example
int run = Race::RunId();
if (Race::IsActive() && run != lastRun && lastRun >= 0)
    retries++;
lastRun = run;

IsComplete

bool Race::IsComplete()

Whether the run has been finished.

Example
if (Race::IsComplete() && !wasComplete)
    completions++;
wasComplete = Race::IsComplete();

TrackKey

string Race::TrackKey()

The track, as a key to keep records by: map:<map> for the game's own tracks, custom:<Workshop id or local>:<file> for custom ones. "" until the race UI has loaded.

Example
string key = Race::TrackKey();
if (key != "")
    Storage::Set("best:" + key, "" + best);

TrackName

string Race::TrackName()

The track's name as its header shows it (the game's own tracks show their number, "01").

Example
nameText.text = Race::TrackName();

TrackAuthor

string Race::TrackAuthor()

Who made the track, as the header shows it; "" on the game's own tracks.

Example
authorText.text = Race::TrackAuthor() == "" ? "" : "by " + Race::TrackAuthor();

TrackImage

string Race::TrackImage()

The track's preview picture, for Window.AddImage: for the game's own tracks the same as Tracks::Image, for a workshop track the .jpg that came with it, for a local map the one it got when it was published; "" if there's none.

Example
string image = Race::TrackImage();
if (image != "")
    window.AddImage(image, 160, 90);

AuthorTime

double Race::AuthorTime()

The track's author time in seconds, from the medal row; 0 until the race has started.

Example
double t = Race::AuthorTime();

IsCustomTrack

bool Race::IsCustomTrack()

Whether the track is a custom one (Workshop or local).

Example
if (Race::IsCustomTrack())
    Log::Info("a custom track");

GetInput

bool Race::GetInput(double &out, double &out, bool &out)

What the player is steering with right now, however they control the ball: x right, y forward (-1 to 1), and whether jump is held. False off a track.

Example
double x, y;
bool jump;
if (Race::GetInput(x, y, jump) && jump)
    jumpLight.visible = true;

SetPaused

bool Race::SetPaused(bool)

Pauses or unpauses the game, as its own pause does (plugins keep running). Returns false if it couldn't. Not during a run that counts (host 0.23.4 and newer): there it returns false; in practice and in editor test runs it pauses.

Example
bool pausedByUs = !Race::IsPaused() && Race::SetPaused(true);
// ... later
if (pausedByUs)
    Race::SetPaused(false);

IsPaused

bool Race::IsPaused()

Whether the game is paused.

Example
if (!Race::IsPaused())
    Race::SetPaused(true);

SaveBall

string Race::SaveBall()

The ball's state as text: where it is, how it's turned, how fast it's going and spinning, and the camera. "" when there's no ball. Keep it as long as you like; give it to LoadBall.

Example
string saved = Race::SaveBall();

LoadBall

bool Race::LoadBall(const string &in, bool momentum = true)

Puts the ball back in a saved state, with its speed (momentum) or standing still. It always makes the run a practice run first (StartPractice), so a run with a restored position can never finish. False without a ball.

Example
if (!Race::LoadBall(saved, true))
    Log::Warn("no ball");

StartPractice

void Race::StartPractice()

Makes this run a practice run: the timer stops and shows 999:999.999, checkpoints and the finish stop responding, and the leaderboard, personal standing and ghosts are hidden. It can't be turned off: it ends by itself when the player restarts, gets a new ball or leaves the map.

Example
Race::StartPractice();

IsPractice

bool Race::IsPractice()

Whether this run is a practice run.

Example
banner.visible = Race::IsPractice();

HideBall

void Race::HideBall(bool)

Hides the player's own ball while true (with the game's special skin actor, the actors the game attached to it and the host's cosmetic models on it), and gives it back with false or when the plugin stops. It's the ball being played, in the track editor's test runs as well. Only how it looks: it still rolls, collides and finishes. For a view of the track without it, such as a ghost viewer.

Example
Race::HideBall(true);

FreezeBall

void Race::FreezeBall(bool)

Holds the player's ball still while true: its input off and its body out of the physics, so it doesn't roll, fall or respawn. false (or the plugin stopping) gives it back as it was: input, physics, speed and spin. For a viewer that shows something else while the ball waits. Only where nothing counts: in the track editor's test runs, in practice or off a race. In a run that can reach a leaderboard it is refused, with a warning in the host log; a ball frozen before such a run starts is given back, and that run doesn't go to a leaderboard. Requires host 0.25.0.

Example
Race::HideBall(true);
Race::FreezeBall(true);       // in an editor test run: the ball waits, hidden, where it is

BallPosition

bool Race::BallPosition(double &out, double &out, double &out)

Where the ball being played is: in a race, and in the track editor's test runs. False when there's none (the main menu, or editing). Requires host 0.15.2.

Example
double x, y, z;
if (Race::BallPosition(x, y, z))
    path.insertLast(x);

BallVelocity

bool Race::BallVelocity(double &out, double &out, double &out)

How fast the ball being played moves: its velocity in cm/s (x, y, z as in BallPosition). False when there's no ball. Requires host 0.26.0.

Example
double vx, vy, vz;
if (Race::BallVelocity(vx, vy, vz))
    speedText.SetText(formatFloat(Math::sqrt(vx * vx + vy * vy) * 0.036, "", 0, 0) + " km/h");

AddBallVelocity

bool Race::AddBallVelocity(double, double, double)

Adds to the ball's velocity this frame (cm/s, world axes): a conveyor belt, a wind, a booster of a map's own. Only on the player's own maps that were never published: one raced from its file (Tracks::OpenLocal) or test-played in the track editor. Anywhere else (the game's tracks, workshop maps, a published map) it does nothing and returns false, with one warning in the host log per track. A run it pushed doesn't go to a Steam leaderboard (a local map's never does), but it still counts for your own plugin's records (Race::RunTainted ignores your own pushes); its timer and checkpoints keep counting as usual. Call it every frame the push lasts, scaled by the frame's time. Requires host 0.26.0.

Example
void Update(float dt)
{
    // a belt along +x at 400 cm/s: the ball is drawn towards its speed
    double vx, vy, vz;
    if (Race::BallVelocity(vx, vy, vz) && onBelt)
        Race::AddBallVelocity((400 - vx) * (dt < 0.33 ? 3 * dt : 1.0), 0, 0);
}

NextBounce

bool Race::NextBounce(double &out strength, double &out x, double &out y, double &out z, double &out nx, double &out ny, 

The next time the ball landed or hit a wall, oldest first; false when there are no more. Each plugin reads its own: the first call starts from now, and each bounce is given once. strength is how hard the hit was, from 0 (a small drop) to 1 (a big landing or a fast wall hit); x, y, z is where the ball touched, and nx, ny, nz the surface's normal there (pointing out of it). ground is true for a floor (a normal pointing up), false for a wall. Rolling and resting don't count. Read them every frame so none wait. Requires host 0.20.0.

Example
double s, x, y, z, nx, ny, nz;
bool ground;
while (Race::NextBounce(s, x, y, z, nx, ny, nz, ground))
    if (s > 0.75)
        Camera::Shake(s);

RunTainted

bool Race::RunTainted(string &out why)

Whether the run (going on, or just finished) must not count for your plugin's own records, and why: practice, a test command that changed the game, the ball moved or frozen by the host or a plugin, game time not at normal speed, or the ball pushed by another plugin. Your own Race::AddBallVelocity pushes (a track mechanic of your own map) don't count. Check it at the finish, before sending a time anywhere. Requires host 0.26.0.

Example
string why;
if (Race::RunTainted(why))
    Log::Info("not sent: " + why);

SetSplitReference

void Race::SetSplitReference(const string &in trackKey, const array<double>@ splits, double total)

Your own split reference for one track: while the race's Race::TrackKey() is trackKey, the delta box under the race timer compares each checkpoint against splits (cumulative seconds from the start, one per checkpoint, in the order they're taken) instead of the player's saved record, and the finish against total (seconds). An empty splits shows no checkpoint deltas, and a total of 0 no finish delta. Nothing is saved: the game's own record stays as it was, and other tracks are untouched. Call it again to change it. Requires host 0.26.0.

Example
array<double> splits = {10.0, 20.0, 30.0};
Race::SetSplitReference(Race::TrackKey(), splits, 41.805);

ClearSplitReference

void Race::ClearSplitReference()

Gives the delta box back to the game's own record. Requires host 0.26.0.

Example
Race::ClearSplitReference();

ClearLocalRecord

bool Race::ClearLocalRecord(const string &in levelName)

Replaces the game's own record of one of the player's own never-published maps (levelName as Race::TrackName shows it) with an empty one: no best time, medal, splits or PB ghost. The game itself writes and saves it, through its own profile save (no save file is touched by the host). For a plugin whose records live elsewhere (its own server). It is done while that map is raced (the game files records by name only, so the map raced must be the player's own never-published one): at once if it is raced now, else the next time it is. True if cleared, queued or there was nothing to clear; false if the map isn't one of the player's own unpublished maps. Requires host 0.26.0.

Example
if (Race::ClearLocalRecord("My Track"))
    Log::Info("the game's own record cleared");

SuppressLocalRecords

bool Race::SuppressLocalRecords(const string &in levelName)

From now on (this game session) the game saves no record for that map: each finish there is marked practice-only in the game's own finish snapshot, so the game keeps it out of its records (time, medal, splits, PB ghost). Only for the player's own never-published maps; false otherwise. A finish is kept out only when the map raced is that never-published map (a track of the same name elsewhere keeps its records). Call it again each game session. Requires host 0.26.0.

Example
Race::SuppressLocalRecords("My Track");

LocalRecordTime

double Race::LocalRecordTime(const string &in levelName)

The game's own best time (seconds) for a map as the profile holds it now; 0 for an empty record, -1 for none. Requires host 0.26.0.

Example
double t = Race::LocalRecordTime("My Track");