Terrain Scripting¶
Event box¶
this simple example will create an oil depot that reacts on trucks that drive into it.
Prerequisites¶
- move nhelens.zip to the
Documents/My Games/Rigs of Rods/mods
folder and unpack all its files to a new directory "nhelens" - remove the old nhelens.zip to prevent collisions
- Enable "Debug Collisions" in your RoR settings ('Settings'>'Diagnostic'>'Debug Collisions') to be able to see the debug visualization for events
- get an oil-well mesh and a fitting .odef file:
http://forumold.rigsofrods.com/index.php?topic=28551.msg355869#msg355869(Needs a new link)
Defining the event box¶
Specified using following keywords:
- boxcoords: Size and position of the box, relatively to the position of the object.
- virtual: specifies that this box is an event box
- event [event_name] [event_type]:
- event_name: the name of the box that the script will get when being notified.
- event_type: valid eventTypes that trigger this: avatar, truck, airplane, delete.
Example:
beginbox
boxcoords 0.0, 20.0, 0.0, 5.0, -4.5, -0.5
virtual
event trigger truck
endbox
Programming the AngelScript file¶
- create a file named
.terrn.as, so in our case the file should be called a1da0UID-nhelens.terrn.as
when the terrain we use is calleda1da0UID-nhelens.terrn
// Always include the base.as file!
#include "base.as"
string calledLast="";
void main()
{
// spawn an oil-well
game.spawnObject("oil-well", "my-oil-well-1", vector3(1119.44f, 33.933f, 924.982f), vector3(0, 0, 0), "myCallBack", false);
}
void myCallBack(int trigger_type, string inst, string box, int nodeid)
{
if(calledLast == inst) return; // already triggered, discard
// we log a message to the logfile
log(inst + " event triggered");
// We show a message ingame
game.flashMessage(inst + " event triggered", 3, -1);
calledLast = inst;
}
Test-Run¶
you should see something like this:
note: We're only interested in the pink boxes here, as they represent event boxes. Light pink boxes do not call back an AngelScript function, while dark pink boxes do call back an AngelScript function when triggered (~when you drive into them).
if you do not see an oil loader, check the AngelScript.log file for errors. With no errors the log could read like this:
ScriptEngine initialized
ScriptEngine (SE) initializing ...
Type registrations done. If you see no error above everything should be working
ScriptEngine running
saving script bytecode to file script_a1da0UID-nhelens.terrn.asc
Executing main()
The script finished successfully.
Result¶
What happens if you drive a truck into the pink event box:
look at your AngelScript.log (on Windows, it's located under Documents\My Games\Rigs of Rods\logs):
02:55:05: SE| my-oil-well-1 event triggered
Whats next¶
you could:
- check if the correct oil tanker trailer is in the spawn box
- direct the user to the oil unloading station after "loading the oil" (sleeping) for some time
- increase the node weight of a certain node inside of the tanker trailer to simulate the loaded oil.
Advanced Examples¶
for example this script will create two oil rigs and will redirect the user to collect and drop oil between them:
#include "base.as"
float timer = 0;
int timerSet = 0;
int state = 0;
vector3 pos_oil1(1099, 33.933, 924.982);
vector3 pos_oil2(1030, 33.4509, 1125.37);
void main()
{
// spawn some oil-wells
game.spawnObject("oil-well", "my-oil-well-1", pos_oil1, vector3(0, 0, 0), "callBackOilWellOne", false);
game.spawnObject("oil-well", "my-oil-well-2", pos_oil2, vector3(0, 0, 0), "callBackOilWellTwo", false);
}
void frameStep(float dt)
{
// count down the timer
if(timer > 0)
timer -= dt;
}
void callBackOilWellOne(int trigger_type, string inst, string box, int nodeid)
{
//if(trigger_type != 1) return; // we only want to trigger on events where the full truck is in the event box (doesn't work at the moment)
if(state != 0) return; // only process this if state is valid
if(timerSet == 0)
{
// set timer
timerSet = 1;
timer = 5;
game.flashMessage("Loading oil ...", timer, -1);
return;
}
if(timerSet == 1 && timer < 0)
{
// timer ran out, do something
game.setDirectionArrow("unload oil", pos_oil2);
state = 1;
timerSet=0;
}
}
void callBackOilWellTwo(int trigger_type, string inst, string box, int nodeid)
{
//if(trigger_type != 1) return; // we only want to trigger on events where the full truck is in the event box (doesn't work at the moment)
if(state != 1) return; // only process this if state is valid
if(timerSet == 0)
{
// set timer
timerSet = 1;
timer = 5;
game.flashMessage("Unloading oil ...", timer, -1);
return;
}
if(timerSet == 1 && timer < 0)
{
// timer ran out, do something
game.setDirectionArrow("load some new oil", pos_oil1);
state = 0;
timerSet=0;
}
}
Adding a race to a terrain¶
In this tutorial, we will add a race to our terrain.
How do races work?¶
In Rigs of Rods, races are added using a script file. The race that we will create in this tutorial will exist out of multiple checkpoints. The objective of the race is to get from the first till the last checkpoint as fast as possible.
We will discuss 2 methods to add a race to your terrain:
- Using a race script generator (fast method);
- Manually creating the script (advanced method).
Adding a race (fast method)¶
You can find a race script generator here.
The checkpoints can be added by specifying the position (x,y,z), rotation (x,y,z) and an object for every checkpoint. This is similar to the old .terrn file syntax, but be aware: do NOT add the checkpoint objects to the terrain using the old .terrn file. The objects will already be spawned by the script.
A checkpoint object is like every other object, but has beside a visible mesh also a virtual event box. The checkpoint will be marked as passed as soon as you drive through the virtual event box.
If you wish, you can also use the default objects, which are available by default in every Rigs of Rods installation. To use these, use objectname "chp-start" for the start and finish line and "chp-checkpoint" for the normal checkpoints. The race script generator will use these objects if you don't specify other objects.
After generating your race, you'll need to copy the script and put it in a new file in your terrain archive. The name of this file should be terrainFileName.terrn.as
. For example, for North Saint Helens, this would become: a1da0UID-nhelens.terrn.as
because the terrain file name of North Saint Helens is a1da0UID-nhelens.terrn
, and we just need to add .as
to that.
Adding a race (advanced method)¶
The easiest way to explain this method is by looking at some examples.
North Saint Helens¶
This example script is usable to add a race to the North Saint Helens terrain (a1da0UID-nhelens.terrn).
Every line that starts with '//' is information that explains the line(s) beneath it.
File: a1da0UID-nhelens.terrn.as
// The following line is required in every script, in order to ensure that
// the spawnpoints keep working. It includes the script inside the file "base.as" here.
#include "base.as"
// We want to add a race, so we will need the race script.
#include "races.as"
// We need to initialize the race script.
racesManager races();
// Here we start the main function.
// A function called 'main' will get called as soon as the terrain has completed loading.
// So inside this function is a perfect spot to tell the game about our races.
void main() {
// We change an option of the races script
// Because of the scattered nature of this race, we want to make sure that
// the user finds his way to the start line of the race.
// So, by setting this option to 'true', we make sure that when the user
// passes a checkpoint when not in a race, the user will still get a
// message informing the user about the race.
races.showCheckPointInfoWhenNotInRace = true;
// For the game to recognize the race, it needs to know where the checkpoints are,
// so we define them in an Array.
// Every line with numbers defines a checkpoint.
// The numbers on a line are from left to right: position X, Y, Z, rotation X, Y, Z
// (with position in meters and rotation in degrees)
// So they're coordinates to uniquely define the location and rotation of an
// object in a three dimensional space.
array<array<double>> coordinates =
{
// { pos X , pos Y , pos Z , rot X , rot Y , rot Z }
{1145.762451, 43.409168, 1874.828247, 0.000000, -20.000000, 0.000000},
{1223.362061, 66.093338, 2128.568359, 0.000000, 30.000000, 0.000000},
{1493.947388, 90.977753, 2490.836426, 0.000000, 55.000000, 0.000000},
{1854.234497, 141.551270, 2732.894287, 0.000000, 65.000000, 0.000000},
{2157.161865, 130.438171, 2720.815430, 0.000000, 90.000000, 0.000000},
{2422.710693, 110.228294, 2523.404785, 0.000000, 140.000000, 0.000000},
{2607.359619, 107.782913, 2203.569824, 0.000000, 165.000000, 0.000000},
{2534.100342, 107.596176, 1938.718140, 0.000000, 205.000000, 0.000000},
{2269.411377, 134.870911, 1729.099121, 0.000000, 265.000000, 0.000000},
{1974.688110, 104.931290, 1732.083618, 0.000000, 245.000000, 0.000000},
{1865.982056, 101.138504, 1618.693237, 0.000000, 245.000000, 0.000000},
{1706.379395, 148.594437, 1533.436157, 0.000000, 255.000000, 0.000000},
{1470.152100, 120.901085, 1504.998291, 0.000000, 310.000000, 0.000000},
// Note: No comma after the last checkpoint.
{1238.410767, 47.336208, 1735.698242, 0.000000, 325.000000, 0.000000}
};
// Now we add the race with name 'Rigbreaker'.
// The last parameter is number of laps.
// * This race has 1 lap.
// * You can use 'races.LAPS_NoLaps' to have no laps
// (~the race start point is not the same checkpoint as the race finish point).
// * You can also use 'races.LAPS_Unlimited' to have a never ending race (~unlimited amount of laps)
races.addRace("Rigbreaker", coordinates, 1);
} // end of the main function
// The default RoR event callback
// This procedure will get called by Rigs of Rods on certain occasions,
// decided by the race script.
void eventCallback(int eventnum, int value) {
// It's not obligated to add this, but it's a good habit.
races.eventCallback(eventnum, value);
}
// end of the script.
Island¶
This example script is usable to add a race to the Island terrain (496aUID-island.terrn).
File: 496aUID-island.terrn.as
#include "base.as"
#include "races.as"
racesManager races();
// The default RoR main function
void main() {
array<array<double>> coordinates = {
{791.551, 87.6567, 1558.25, 0.0, 35.3333, 0.0},
{970.905, 119.2 , 1421.01, 0.0, -93.6470, 0.0},
{1350.28, 157.644, 1375.19, 0.0, -44.4060, 0.0},
{1506.18, 180.185, 1309.12, 0.0, 29.4644, 0.0},
{1306.9 , 209.358, 1250.37, 0.0, 70.3679, 0.0},
{940.346, 236.788, 926.603, 0.0, 16.9539, 0.0}
};
races.addRace("To The Top", coordinates, races.LAPS_NoLaps);
}
// The default RoR event callback
void eventCallback(int eventnum, int value) {
races.eventCallback(eventnum, value);
}
Bajarama¶
This example script shows a race with an unlimited amount of laps (a never ending race). It is usable with the Bajarama terrain (8c07UID-bajarama.terrn).
File: 8c07UID-bajarama.terrn.as
#include "base.as"
#include "races.as"
racesManager races();
void main() {
array<array<double>> coords1 = {
{179.088196, 1.351834, 203.319107, -0.000006, 75.500044, -0.849956},
{56.070511, 1.247547, 119.811401, 0.000001, 109.500097, 1.700087},
{88.742783, 2.674362, 332.812042, 0.000071, 127.500016, -7.299959},
{157.537796, 1.121414, 478.227203, 0.595164, -29.497634, -0.456070},
{202.784286, 1.830205, 240.792023, 0.446688, -87.490632, -2.408985},
{326.742004, 1.115725, 436.851685, 0.000000, 0.000003, -0.200001},
{360.338379, 1.100020, 102.170441, 0.000033, -140.500010, -0.700087},
{482.216766, 1.089854, 430.449249, 0.000000, 0.000000, -0.500001},
{478.902618, 1.325789, 90.371094, 0.000000, -0.000014, 0.000000},
{92.562027, 1.122820, 86.679283, 0.000002, -91.000017, 0.000002},
{264.193359, 1.481601, 121.791405, 0.000000, -179.999991, -0.700000}
};
// race name coordinates #laps checkpoint object startline object
int raceID = races.addRace("Bajarama", coords1, races.LAPS_Unlimited, "new-checkpoint", "new-checkpoint-start");
}
// The default RoR event callback
void eventCallback(int eventnum, int value) {
races.eventCallback(eventnum, value);
}
Flat Map (v10.1)¶
This example script illustrates how to add multiple races to one terrain and is usable for the Flat Map terrain (f4afUID-flat_map_full32xa.terrn).
File: f4afUID-flat_map_full32xa.terrn.as
#include "base.as"
#include "races.as"
racesManager races();
void main() {
// We add 4 races to the map
// RACE 1: Dirt drag race - right side
array`<array<double>`> coords1 = {
{2293.272705, 0.0, 2035.251465, 0.0, 0.0, 0.0},
{2293.272705, 0.0, 1484.145752, 0.0, 0.0, 0.0}
};
// race name coordinates #laps
int raceID = races.addRace("Dirt DragRace - Right Side", coords1, races.LAPS_NoLaps);
// race 1 added and working
// RACE 2: Dirt drag race - left side
array`<array<double>`> coords2 = {
{2268.944580, 0.0, 2035.251465, 0.0, 0.0, 0.0},
{2268.944580, 0.0, 1484.145752, 0.0, 0.0, 0.0}
};
// race name coordinates #laps
int raceID = races.addRace("Dirt DragRace - Left Side", coords2, races.LAPS_NoLaps);
// race 2 added and working
// RACE 3: Runway drag race - left side
array`<array<double>`> coords3 = {
{2327.494141, 1.0, 1388.388794, 0.0, 0.0, 0.0},
{2327.494141, 1.0, 932.558044 , 0.0, 0.0, 0.0}
};
// race name coordinates #laps
int raceID = races.addRace("Runway DragRace - Left Side", coords3, races.LAPS_NoLaps);
// race 3 added and working
// RACE 4: Runway drag race - right side
array`<array<double>`> coords4 = {
{2343.309814, 1.0, 1388.388794, 0.0, 0.0, 0.0},
{2343.309814, 1.0, 932.558044 , 0.0, 0.0, 0.0}
};
// race name coordinates #laps
int raceID = races.addRace("Runway DragRace - Right Side", coords4, races.LAPS_NoLaps);
// race 4 added and working
}
// The default RoR event callback
void eventCallback(int eventnum, int value) {
races.eventCallback(eventnum, value);
}
F1 Test Track¶
This example script illustrates how to use custom checkpoint objects and multiple races on one terrain. The script can be used with the F1 Test Track terrain (2af11UID-f1_testtrack.terrn).
File: 2af11UID-f1_testtrack.terrn.as
#include "base.as"
#include "races.as"
racesManager races();
// The default RoR main function
void main() {
// We add 5 races to the map
// RACE 1
array<array<double>> coords1 = {
{ 882.132996, 0.120613, 1324.317139, 0.0, 90.0, 0.0},
{ 658.905884, 0.076029, 1324.323730, 0.0, 90.0, 0.0},
{ 575.903259, 0.062041, 1231.623169, 0.0, 0.0, 0.0},
{ 565.184814, 0.063519, 1037.515503, 0.0, 22.0, 0.0},
{ 313.121979, 0.079952, 822.904663, 0.0, 5.0, 0.0},
{ 385.599213, 0.071390, 722.493469, 0.0, -90.0, 0.0},
{ 770.934998, 0.012638, 761.321411, 0.0, -90.5, 0.0},
{1055.889404, 0.078151, 664.507324, 0.0, -89.0, 0.0},
{1388.452026, 0.030632, 663.976257, 0.0, 92.0, 0.0},
{1457.364014, 0.041678, 783.509460, 0.0, 168.0, 0.0},
{1493.774048, 0.104160, 1309.505859, 0.0, 18.5, 0.0},
{1348.787964, 0.099335, 1324.566406, 0.0, 90.0, 0.0},
{ 909.298462, 0.044833, 1324.610596, 0.0, 88.5, 0.0}
};
// race name coordinates #laps checkpoint object startline object finishline object
int raceID = races.addRace("Grand Prix long", coords1, races.LAPS_NoLaps, "new-checkpoint", "new-checkpoint-start", "new-checkpoint-start");
// race 1 added and working
// RACE 2
array<array<double>> coords2 =
{
{1176.429688, 0.063195, 1254.195313, -0.0, 90.0, 0.0},
{ 693.874573, 0.090642, 1251.470825, -0.0, 90.0, 0.0},
{ 693.383728, 0.071324, 1182.933594, -0.0, -90.0, 0.0},
{ 844.552612, 0.095163, 1168.225586, -0.0, -90.0, 0.0},
{ 941.776978, 0.052285, 1183.067139, -0.0, -90.0, 0.0},
{1079.778198, 0.096842, 1183.057373, -0.0, -90.0, 0.0},
{1177.627563, 0.067999, 1125.772461, -0.0, -40.0, 0.0},
{1282.897095, 0.938393, 1045.571899, 0.0, -90.0, 0.0},
{1395.055054, 0.107390, 1148.677734, -0.0, 0.0, 0.0},
{1290.430908, 0.098327, 1254.477905, 0.0, 90.0, 0.0}
};
// race name coordinates #laps checkpoint object startline object finishline object
raceID = races.addRace("Grand Prix short", coords2, races.LAPS_NoLaps, "new-checkpoint", "new-checkpoint-start", "new-checkpoint-start");
// race 2 added and working
// RACE 3
array<array<double>> coords3 =
{
{1117.230103, 0.067576, 700.704956, 0.0, -90.0, 0.0},
{1136.480469, 0.072812, 1030.468628, 0.0, 90.0, 0.0},
{1101.686768, 0.032589, 701.005127, 0.0, -90.0, 0.0}
};
// race name coordinates #laps checkpoint object startline object finishline object
raceID = races.addRace("oval race", coords3, races.LAPS_NoLaps, "new-checkpoint", "new-checkpoint-start", "new-checkpoint-start");
// race 3 added and working
// RACE 4
array<array<double>> coords4 =
{
{1187.875977, 0.0, 1220.567383, 0.0, 90.0, 0.0},
{ 784.379578, 0.0, 1221.171143, 0.0, -90.0, 0.0}
};
// race name coordinates #laps checkpoint object startline object finishline object race version
raceID = races.addRace("drag race", coords4, races.LAPS_NoLaps, "new-checkpoint", "new-checkpoint-start", "new-checkpoint-start");
// race 4 added and working
// RACE 5
double[][] coords5 =
{
// x z y 3d rot rot 3d rot
{ 807.868, 5.09987, 1114.47, 0.0, -90.0, 0.0},
{ 724.386, 0.0994606, 1084.16, 0.0, 0.0, 0.0},
{ 718.647, 0.0998037, 1038.22, 0.0, 45.0, 0.0},
{ 696.235, 0.0989883, 992.215, 0.0, -25.0, 0.0},
{ 754.302, 0.098882, 999.441, 0.0, 0.0, 0.0},
{ 763.464, 0.0987995, 1049.56, 0.0, 45.0, 0.0},
{ 831.675, 5.01375, 1058.26, 0.0, 90.0, 0.0},
{ 919.557, 0.0995347, 1083.47, 0.0, 0.0, 0.0},
{ 884.884, 0.0987005, 1121.12, 0.0, -90.0, 0.0}
};
// race name coordinates #laps (no checkpoint objects are specified here, so the default RoR ones will be used)
raceID = races.addRace("mud race", coords5, 3);
// race 5 added and working
}
// The default RoR event callback
void eventCallback(int eventnum, int value) {
races.eventCallback(eventnum, value);
}
F1 Test Track (with penalty events)¶
We can also penalty events if the player hits a specific part of the checkpoint.
For this race, we've edited the 2af11UID-new-checkpoint.odef file from f1track_improved.zip to have penalty event boxes:
2af11UID-new-checkpoint.mesh 1, 1, 1
beginbox boxcoords -7.5, 6.95, -4.0, 5.2, -0.5, 0.5 virtual event checkpoint truck endbox
beginbox boxcoords -8.6, -7.65, 0.0, 0.55, -0.65, 0.0 virtual event race_penalty truck endbox
beginbox boxcoords 8.05, 7.1, 0.0, 0.55, -0.65, 0.0 virtual event race_penalty truck endbox
end
As you can see, there are 2 small event boxes that will trigger the penalty event. The penalty event will, when triggered, add an amount of seconds to the lap time. How many seconds can be configured using the races.setPenaltyTime(int raceID, int seconds) method or you can just change it using the PenaltyEvent callback function.
We'll also need this PenaltyEvent callback function when we want to show a message if a penalty event was triggered. For this we'll need to:
- Define the callback function ('on_penaltyEvent' in the script below)
- Tell the races script about this callback function ('races.setCallback("PenaltyEvent", on_penaltyEvent);')
This is all done in the following script. Pay attention to every difference with the script above.
#include "base.as"
#include "races.as"
racesManager races();
// The default RoR main function
void main() {
// the penalty event shows no message by default, so we'll have to show a message ourself.
races.setCallback("PenaltyEvent", on_penaltyEvent);
// We add 5 races to the map
// RACE 1
array <array<double> > coords1 = {
{ 882.132996, 0.120613, 1324.317139, 0.0, 90.0, 0.0},
{ 658.905884, 0.076029, 1324.323730, 0.0, 90.0, 0.0},
{ 575.903259, 0.062041, 1231.623169, 0.0, 0.0, 0.0},
{ 565.184814, 0.063519, 1037.515503, 0.0, 22.0, 0.0},
{ 313.121979, 0.079952, 822.904663, 0.0, 5.0, 0.0},
{ 385.599213, 0.071390, 722.493469, 0.0, -90.0, 0.0},
{ 770.934998, 0.012638, 761.321411, 0.0, -90.5, 0.0},
{1055.889404, 0.078151, 664.507324, 0.0, -89.0, 0.0},
{1388.452026, 0.030632, 663.976257, 0.0, 92.0, 0.0},
{1457.364014, 0.041678, 783.509460, 0.0, 168.0, 0.0},
{1493.774048, 0.104160, 1309.505859, 0.0, 18.5, 0.0},
{1348.787964, 0.099335, 1324.566406, 0.0, 90.0, 0.0},
{ 909.298462, 0.044833, 1324.610596, 0.0, 88.5, 0.0}
};
// race name coordinates #laps checkpoint object startline object finishline object
int raceID = races.addRace("Grand Prix long", coords1, races.LAPS_NoLaps, "new-checkpoint", "new-checkpoint-start", "new-checkpoint-start");
races.setPenaltyTime(raceID, 10); // <- this sets the default penalty time (in seconds) for this race when a race_penalty event occurs.
// race 1 added and working
// RACE 2
array<array<double> > coords2 =
{
{1176.429688, 0.063195, 1254.195313, -0.0, 90.0, 0.0},
{ 693.874573, 0.090642, 1251.470825, -0.0, 90.0, 0.0},
{ 693.383728, 0.071324, 1182.933594, -0.0, -90.0, 0.0},
{ 844.552612, 0.095163, 1168.225586, -0.0, -90.0, 0.0},
{ 941.776978, 0.052285, 1183.067139, -0.0, -90.0, 0.0},
{1079.778198, 0.096842, 1183.057373, -0.0, -90.0, 0.0},
{1177.627563, 0.067999, 1125.772461, -0.0, -40.0, 0.0},
{1282.897095, 0.938393, 1045.571899, 0.0, -90.0, 0.0},
{1395.055054, 0.107390, 1148.677734, -0.0, 0.0, 0.0},
{1290.430908, 0.098327, 1254.477905, 0.0, 90.0, 0.0}
};
// race name coordinates #laps checkpoint object startline object finishline object
raceID = races.addRace("Grand Prix short", coords2, races.LAPS_NoLaps, "new-checkpoint", "new-checkpoint-start", "new-checkpoint-start");
races.setPenaltyTime(raceID, 10); // <- this sets the default penalty time (in seconds) for this race when a race_penalty event occurs.
// race 2 added and working
// RACE 3
array<array<double> > coords3 =
{
{1117.230103, 0.067576, 700.704956, 0.0, -90.0, 0.0},
{1136.480469, 0.072812, 1030.468628, 0.0, 90.0, 0.0},
{1101.686768, 0.032589, 701.005127, 0.0, -90.0, 0.0}
};
// race name coordinates #laps checkpoint object startline object finishline object
raceID = races.addRace("oval race", coords3, races.LAPS_NoLaps, "new-checkpoint", "new-checkpoint-start", "new-checkpoint-start");
races.setPenaltyTime(raceID, 10); // <- this sets the default penalty time (in seconds) for this race when a race_penalty event occurs.
// race 3 added and working
// RACE 4
array<array<double> > coords4 =
{
{1187.875977, 0.0, 1220.567383, 0.0, 90.0, 0.0},
{ 784.379578, 0.0, 1221.171143, 0.0, -90.0, 0.0}
};
// race name coordinates #laps checkpoint object startline object finishline object race version
raceID = races.addRace("drag race", coords4, races.LAPS_NoLaps, "new-checkpoint", "new-checkpoint-start", "new-checkpoint-start");
races.setPenaltyTime(raceID, 10); // <- this sets the default penalty time (in seconds) for this race when a race_penalty event occurs.
// race 4 added and working
// RACE 5
double[][] coords5 =
{
// x z y 3d rot rot 3d rot
{ 807.868, 5.09987, 1114.47, 0.0, -90.0, 0.0},
{ 724.386, 0.0994606, 1084.16, 0.0, 0.0, 0.0},
{ 718.647, 0.0998037, 1038.22, 0.0, 45.0, 0.0},
{ 696.235, 0.0989883, 992.215, 0.0, -25.0, 0.0},
{ 754.302, 0.098882, 999.441, 0.0, 0.0, 0.0},
{ 763.464, 0.0987995, 1049.56, 0.0, 45.0, 0.0},
{ 831.675, 5.01375, 1058.26, 0.0, 90.0, 0.0},
{ 919.557, 0.0995347, 1083.47, 0.0, 0.0, 0.0},
{ 884.884, 0.0987005, 1121.12, 0.0, -90.0, 0.0}
};
// race name coordinates #laps (no checkpoint objects are specified here, so the default RoR ones will be used)
raceID = races.addRace("mud race", coords5, 3);
// race 5 added and working
}
// The default RoR event callback
void eventCallback(int eventnum, int value)
{
races.eventCallback(eventnum, value);
}
void on_penaltyEvent(dictionary@ info)
{
// this method gets called every time a race_penalty event occurs.
// We can also change the penalty time here:
info.set("penaltyTime", 10);
// But the penalty time was already set to 10 seconds, because we had set it to 10 in the main() function.
// So now we've set it twice to 10 seconds, which is quite pointless...
// Just show a message to inform the user about the penalty
races.message("PENALTY", "lightning.png");
}
Notes:
- We've only used the 'race_penalty' event here, but you can also use the 'race_abort' event, which will abort the race when the event box is triggered.
- Another way to add penalty seconds is using the races.addPenaltySeconds(int seconds) method.
- You can also register callback functions for other events: https://developer.rigsofrods.org/d9/dce/class_script2_script_1_1races_manager.html
More Advanced Functionality¶
Documentation and questions¶
See reference manual. Studying the script files of other terrains may also greatly help you.
In case of questions/suggestions/complains, get in touch in the forums.
Example: Extending RacesManager¶
Here's an example where we inherit from the racesManager class and add functionality. (In this case, we limit the allowed vehicles, so the race won't start if certain vehicles aren't used). You can test this script by adding it to the North Saint Helens terrain.
#include "base.as";
#include "races.as";
racesManagerWithVehicleLimit races();
void main() {
// Add the race like usual
array < array<double> > coords1 = {
{1140.259644, 34.136135, 920.070313, 0.0, 0.0, 0.0},
{1140.259644, 34.136135, 950.070313, 0.0, 0.0, 0.0}
};
int raceID_testRace = races.addRace("testRace", coords1, races.LAPS_NoLaps);
// Add some vehicles (when you don't add any vehicles, then all vehicles will be allowed)
races.addVehicle(raceID_testRace, "Bus RVI agora S");
races.addVehicle(raceID_testRace, "Bus RVI agora L");
}
// Other stuff (No race specific stuff under this line)
class racesManagerWithVehicleLimit : racesManager {
dictionary vehicleData;
double lastMessageTime;
racesManagerWithVehicleLimit()
{
super();
lastMessageTime = 0.0;
}
// extend this method
void startRace(int raceID) /*override*/
{
bool allow = true;
// Do we have vehicle data for this race?
array <string> @ vehicles = null;
if(vehicleData.get("race_"+raceID, @vehicles))
{
// Get the name of the current truck
string truckName = "avatar";
BeamClass@ truck = game.getCurrentTruck();
if(truck !is null)
truckName = truck.getTruckName();
if(vehicles.find(truckName) <0)
allow = false;
}
if(allow)
racesManager::startRace(raceID);
else
{
// Avoid message spam (in exceptional cases)
if((game.getTime()-this.lastMessageTime)> 5.0)
{
this.lastMessageTime = game.getTime();
this.message("Race "+this.raceList[raceID].raceName+" can only be started with one of the following vehicles:", "information.png");
this.message(arrayToString(vehicles), "information.png");
}
}
}
void addVehicle(int raceID, string vehicleName)
{
array <string> @ vehicles = null;
if(!vehicleData.get("race_"+raceID, @vehicles))
{
array <string> vehicles2 = {};
@vehicles = @vehicles2;
vehicleData.set("race_"+raceID, @vehicles);
}
vehicles.insertLast(vehicleName);
}
}
string arrayToString(array<string>@ arr) {
string result = "";
if(arr !is null) for(uint i=0; i<arr.length(); ++i)
{
result += arr[i];
if(i!=arr.length()-1) result += ", ";
}
return result;
}
Troubleshooting¶
If your race doesn't work, feel free to post your terrain file in this forum, and we may have a look at it. https://forum.rigsofrods.org/forums/content-support.10/