VrxScript API Documentation
The official modding language for Galactic Prospectors and Starbreaker, built into the Vyrex Engine and the Vyrex Editor.
Getting Started
VrxScript is a small, safe scripting language for modding both Vyrex Engine games. You write plain-text .vrx source files in the Vyrex Editor, hit Compile, and get a sealed .vrxscr file the games load automatically. Only the Vyrex Editor and the games can read, run, or decompile sealed scripts.
- Open the Vyrex Editor and create a mod (pick your game: Galactic Prospectors or Starbreaker).
- In the Scripts tab, click New Script..., write your code (Ctrl+Space for suggestions), then Compile.
- Copy your mod folder into the game's
Modsdirectory (or build it there directly):
| Game | Mods folder |
|---|---|
| Galactic Prospectors | %APPDATA%\GalacticProspectors\Mods\ |
| Starbreaker | %APPDATA%\VyrexEngine\3D\GalacticProspectors\Mods\ |
Launch the game and enter a world - your scripts load automatically and on init fires. That's it.
// my_first_mod.vrx - the smallest possible mod
on init {
game.toast("Hello from my first mod!");
}
Mod Structure
Every mod is a folder with a manifest and five standard subfolders. The Vyrex Editor scaffolds all of this for you.
MyMod/
mod.vrxcfg # manifest: name, author, version, game, description
Scripts/ # sealed .vrxscr scripts (+ your .vrx sources)
Textures/ # .vrxtex textures (import PNG in the editor)
Models/ # .vrxmdl models (import OBJ in the editor)
Animations/ # .vrxanm animations (import JSON in the editor)
Data/ # config overrides (.roid XML for GP, .vrxcfg for Starbreaker)
The manifest is human-readable:
mod "Meteor Madness" {
author = "you"
version = "1.0.0"
game = starbreaker # or: galacticprospectors
description = "Regular meteor showers with bonus ore."
}
The Language
VrxScript is C-style: braces, semicolons, // and /* */ comments. It has five value types: numbers (64-bit float), strings, booleans, null, and arrays.
Variables
var credits = 100;
var name = "Prospector";
var active = true;
var nothing = null;
var list = [1, 2, 3];
credits += 50; // also -= *= /=
list[0] = 99; // index read/write
Variables declared at the top level of a script are globals - they keep their values between events and are shared by all handlers in the same script. Variables declared inside a function or handler are local to it.
Control flow
if (credits >= 1000 && active) {
game.log("rich!");
} else {
game.log("keep mining");
}
while (credits < 500) {
credits += 10;
if (credits == 300) break; // continue; works too
}
for (var i = 0; i < len(list); i += 1) {
game.log("item " + list[i]);
}
Operators: + - * / %, comparisons == != < > <= >=, logic && || !. + concatenates when either side is a string. && and || short-circuit.
Functions
fn reward_for(kills) {
return kills * 150;
}
on init {
player.add_money(reward_for(3));
}
Events
Handlers are declared with on. A script can define any subset of them.
Runs once when your mod loads (world entry). Use it for setup and a hello toast.
Runs every frame during gameplay. dt is the time in seconds since the last tick (typically 0.016). Keep per-tick work small - accumulate dt for timers.
Fires once per key press during gameplay for "A"-"Z", "0"-"9" and "F1"-"F12". This is how you build custom keybinds. Not fired while the chat box is open.
on key(name) {
if (name == "F6") { game.toast("custom keybind!"); }
}Sandbox & Limits
Scripts run in a hard sandbox. The only way a script touches the game is through the functions documented on this page - there is no file, network, or reflection access, and none will be added.
- Multiplayer-safe: every world-mutating call (marked host/SP) silently does nothing on a multiplayer client. Mods can never desync a server. Multiplayer/network internals are not exposed to scripts, by design, ever.
- Fuel limit: each event may execute ~200,000 instructions. Runaway loops are stopped with a script error instead of freezing the game.
- Recursion cap (64 frames) and array bounds checks - errors, not crashes.
- Auto-disable: a script that errors 8 times is disabled for the session and logged.
- Unknown API calls are detected at load time; the script is skipped with a clear log message (check the target game of your mod!).
%APPDATA%\GalacticProspectors\Logs\Game.log. Starbreaker: %APPDATA%\VyrexEngine\3D\GalacticProspectors\game.log. Look for lines starting with [Mods] / [Mod].Shared API both games
game.*
Writes a line to the game log, prefixed [Mod]. Your best debugging tool.
game.log("credits are now " + player.get_money());
Plays a named sound event through the game's audio system. gain is 0..1 (default 1). Unknown names are ignored safely.
game.play_sound("toast", 0.6);
Seconds of gameplay since the world was entered (only counts while actually playing).
input.*
True while a key is physically held. Same key names as on key: "A"-"Z", "0"-"9", "F1"-"F12". Combine with on tick for hold-style controls.
on tick(dt) {
if (input.is_down("B")) { game.log("B is held"); }
}
player.*
Current credit balance.
Adds (or with a negative value, removes) credits.
Current hull health.
Maximum hull health.
Restores up to n health, clamped at max.
world.*
Number of live hostiles around you.
Number of loaded asteroids around you.
Galactic Prospectors API 2D
Everything in the Shared API, plus:
game.*
Shows an on-screen notification with a title and message.
game.toast("My Mod", "Something happened!");
player.*
Player ship X position.
Player ship Y position.
Instantly moves the player ship.
// panic button: jump 2000 units up on F9
on key(name) {
if (name == "F9") {
player.teleport(player.get_x(), player.get_y() - 2000);
world.spawn_warp_fx(player.get_x(), player.get_y());
}
}
Scrap currently carried.
Adds scrap, or removes it with a negative value. Never goes below zero.
Sets hull health directly, clamped to the maximum.
Takes n off the hull. Stops at zero rather than going negative.
Changes the hull's maximum. Current health is pulled down to fit if it has to be.
Ship velocity along X, units per second.
Ship velocity along Y, units per second.
Sets the ship's velocity outright. Useful for a shove, a tractor pull or a hard stop.
// emergency brake on F10
on key(name) {{
if (name == "F10") {{
player.set_velocity(0, 0);
game.toast("Brake", "All stop.");
}}
}}
How fast the ship is going, whatever the direction.
Boost charge remaining, 0 to 100.
Current gun heat.
The heat level at which the guns cut out.
Sets gun heat. Drop it to zero for a coolant pack, raise it to punish something.
True while the player is out of the ship in their suit.
False once the hull is at zero.
The id of the hull the player is flying, matching Ships.vrxcfg.
Which sector the player is in, by name.
world.*
Live AI vessels nearby.
Stations in the loaded sector.
Spawns one AI vessel by its id from AIVessels.vrxcfg, at a position.
// an ambush where the player is standing
var p = player.get_x() + 600;
world.spawn_vessel("void_pirate_scout", p, player.get_y());
The closest live asteroid to a point, or to the player if no point is given. Comes back as "x,y", or empty if there is none.
The closest live hostile, as "x,y", or empty.
The closest station, as "x,y", or empty.
Straight-line distance between two points.
True when this world has other players in it.
True when this machine decides what happens. Every call marked host-only does nothing when this is false, so check it before building on one.
Spawns an asteroid at a position. scale ~0.5 (small) to 2.0 (huge), 1.0 = normal.
Spawns one hostile ship using the game's normal hostile-spawn rules.
Plays the warp-in visual effect at a position. Cosmetic only, safe anywhere.
cargo.*
How many distinct items are in the active hold.
How much of one item is held. The id is the item's guid, as it appears in Craftables.vrxcfg or Resources.vrxcfg.
Puts items in the hold. amount defaults to 1 and may be negative.
Takes items out of the hold, stopping at empty.
Every item id in the hold, comma separated. Split it to walk the hold.
enemy.*
How many live hostiles are inside a circle.
Destroys the closest hostile to a point, or to the player if no point is given.
asteroid.*
How many live asteroids are inside a circle.
faction.*
Your standing with an AI faction, by its id from Factions.vrxcfg.
Moves your standing with a faction up or down.
True while that faction is at war with you.
ui.*
Writes a line into the in-game chat, the way the game announces things.
Drops a GPS marker the player can navigate to.
var rock = world.nearest_asteroid();
if (rock != "") {{
ui.add_marker("Survey target", 0, 0);
}}
data.*
Reads a value straight out of a .vrxcfg content file, including a mod's override of it. The path walks child nodes with /, and Kind[id] picks one by id.
var hp = data.get("AIVessels", "Vessel[void_pirate_scout]/Health");
game.log("scout has " + hp + " hull");
Every id of one kind in a data file, comma separated. Walk it to react to whatever content is installed rather than a hardcoded list.
var all = data.ids("AIVessels", "Vessel");
game.log("vessel types: " + all);
server.*
Posts a SERVER chat line every player sees.
server.broadcast("Double ore weekend is live!");
Sends a private server notice (toast) to one player by SteamID string.
Names of all connected players.
Number of connected players.
Display name for a SteamID string.
SteamID string of the connected player with that display name (case-insensitive), or null.
True when that SteamID has Admin (or higher) permission on this server. Always gate kick/give commands with this.
Kicks a player (same path as the admin panel). Cannot kick the host.
Grants credits to a player through the host-authoritative reward pipe.
Grants scrap to a player through the host-authoritative reward pipe.
Starbreaker API 3D
Everything in the Shared API, plus:
game.*
Shows a HUD notification. Optional hex color, default "#7FE9FF".
game.toast("Something happened!", "#FFB63D");
player.*
The player ship's position as an array [x, y, z] - handy for math.
var p = player.get_pos();
game.log("at " + p[0] + ", " + p[1] + ", " + p[2]);
Player ship X position.
Player ship Y position.
Player ship Z position.
Instantly moves the player ship and zeroes its velocity.
Current shield points.
Current ship speed in m/s.
Ore units currently in the hold.
Total cargo hold size.
Grants missiles (capped at 20 total) and decoys (capped at 10).
Adds ore directly to your cargo hold, respecting free capacity. Ore names match the in-game deposits, e.g. "Iron", "Copper", "Titanium", "Platinum".
var granted = player.give_ore("Iron", 25);
game.toast("Received " + granted + " iron");
world.*
Spawns an ore asteroid. oreType is the ore index (0 = Iron, 1 = Copper, 2 = Titanium, 3 = Platinum...), ore is the amount it holds.
Spawns a pirate group (1-8 ships) centered on a position. They will come for you.
Scatters collectible ore pickups: units total ore split across drops pieces around the position.
Position of the closest live asteroid as [x, y, z], or null if none are loaded.
var rock = world.nearest_asteroid();
if (rock != null) {
var p = player.get_pos();
var d = sqrt(pow(rock[0]-p[0],2) + pow(rock[1]-p[1],2) + pow(rock[2]-p[2],2));
game.toast("Nearest rock: " + round(d) + " m");
}
Builtins both games
Pure functions, always available, no game access.
| Function | Description |
|---|---|
abs(n) | Absolute value. |
floor(n) | Round down. |
ceil(n) | Round up. |
round(n) | Round to nearest. |
sqrt(n) | Square root. |
pow(base, exp) | Exponentiation. |
min(a, b) | Smaller of two. |
max(a, b) | Larger of two. |
clamp(n, lo, hi) | Constrain to a range. |
sin(rad) | Sine (radians). |
cos(rad) | Cosine (radians). |
atan2(y, x) | Angle of a vector (radians). |
random() | Random number 0..1. |
random_range(a, b) | Random number in [a, b). |
random_int(a, b) | Random whole number in [a, b] inclusive. |
str(v) | Convert any value to a string. |
num(s) | Parse a number (null on failure). |
len(v) | Length of a string or array. |
upper(s) | Uppercase. |
lower(s) | Lowercase. |
contains(s, sub) | Case-insensitive substring test. |
substring(s, start [, count]) | Slice a string. |
split(s, sep) | Split a string into an array. |
push(arr, v) | Append to an array. |
pop(arr) | Remove and return the last element. |
remove_at(arr, i) | Remove the element at an index. |
index_of(arr, v) | Find the index of a value (-1 if absent). |
Cookbook: Example Mods
1. Custom keybind toolkit both games
// Bind gameplay actions to any key you like.
on key(name) {
if (name == "F5") { game.toast("Balance: " + player.get_money()); }
if (name == "F6") { player.heal(100); game.play_sound("toast"); }
if (name == "F7") { game.log("time: " + round(game.time()) + "s"); }
}
2. Meteor shower events Starbreaker
var next_shower = 120;
on tick(dt) {
if (game.time() < next_shower) return;
next_shower = game.time() + random_range(180, 360);
game.toast("Meteor shower incoming!", "#FFB63D");
var p = player.get_pos();
for (var i = 0; i < 5; i += 1) {
world.spawn_asteroid(
p[0] + random_range(-400, 400),
p[1] + random_range(300, 600),
p[2] + random_range(-400, 400),
random_int(0, 3), random_int(40, 90));
}
}
3. Hardcore mode Galactic Prospectors
// More pirates when you get rich - risk scales with wealth.
var timer = 0;
on tick(dt) {
timer += dt;
if (timer < 60) return;
timer = 0;
var wealth_waves = clamp(floor(player.get_money() / 50000), 0, 4);
for (var i = 0; i < wealth_waves; i += 1) {
world.spawn_pirate();
}
if (wealth_waves > 0) {
game.toast("Bounty Hunters", "Your wealth attracts attention...");
}
}
4. Mining assistant Starbreaker
// Press M for a range ping to the nearest rock + cargo report.
on key(name) {
if (name != "M") return;
var rock = world.nearest_asteroid();
if (rock == null) { game.toast("No asteroids nearby"); return; }
var p = player.get_pos();
var d = sqrt(pow(rock[0]-p[0],2) + pow(rock[1]-p[1],2) + pow(rock[2]-p[2],2));
var hold = player.get_cargo_count() + "/" + player.get_cargo_capacity();
game.toast("Rock " + round(d) + " m | Cargo " + hold);
}
5. Daily login bonus both games
var paid = false;
on tick(dt) {
if (paid || game.time() < 10) return;
paid = true;
player.add_money(500);
game.play_sound("toast");
game.log("login bonus granted");
}