Wolf systems
Driving: the car, truck and bike dashboard
Sit in a vehicle and a full dashboard appears across the bottom of the screen: a real speedometer and rev counter, gears you change yourself, lamps, indicators, a horn, and a steering wheel and pedals you can drive with the mouse, a wheel or a gamepad.
Wolf Territories only. This needs WolfViewer or WolfStorm on a Wolf Territories region. On other grids the menu items, buttons and panels are not shown at all.
Other viewers drive vehicles with the normal keys (arrows or W A S D, Page Up and Page Down), exactly as before. Vehicle scripts keep working for them.
Overview

How it opens
- By itself when you sit on something physical (a vehicle being driven), or when the vehicle’s script sends the dashboard its readings. It opens once for each seat; close it and it stays closed until you sit down again.
- World > Car Dashboard in the menu bar, any time.
- The car icon in the bottom-right corner of the screen, beside the Toolbar, Game, Plane and Boat icons. It is lit while the dashboard shows. There is also a Dashboard button you can put on a toolbar.
- X on the dashboard closes it.
One panel uses the bottom of the screen at a time. Opening the dashboard switches Flight or Sailing Mode off, and the Wolf Roleplay game bar gives up the bottom while the dashboard shows.
Three designs
Each is modelled on a real vehicle. Pick one with the CAR, TRUCK and BIKE buttons; your choice is remembered for that vehicle, and a vehicle’s script can choose one too.
Car
After the Porsche 911 (992) cluster: the analogue rev counter in the middle between the speedometer and an information dial, red needles in the BMW M style, and standard warning lamps. Eight gears, manual or automatic (P R N D).
Truck
After the Scania R 450 with its 12-speed range-splitter gearbox (Opticruise): a low-revving rev counter with its green economy band, a speedometer with the 90 km/h limiter, the gear with its range (LOW / HIGH) and split, twin air-brake pressure needles, fuel and AdBlue, the retarder, and the tachograph’s driving time and break countdown. Manual or automatic (R N A).
Bike
After the BMW S 1000 RR and Ducati Panigale colour screens: a bar rev counter across the top with a shift light, the gear in the middle, digital speed and your lean angle, with handlebars instead of a wheel. A sequential box: 1 N 2 3 4 5 6.
Using the dashboard

The buttons along the top
| Button | What it does |
|---|---|
| CAR / TRUCK / BIKE | The three designs. The lit one is showing. |
| KM/H or MPH | The speed units. Click to switch. |
| TRIP 0 | Resets the trip meter (and the bike's lean record). |
| PANEL | The background on or off. With it off only the instruments and controls are drawn, and clicks in the gaps reach the world. |
| MAP | The World Map, centred on where you are driving. |
| CONTROLS | Driving Controls: a steering wheel, pedals or gamepad, and the keys for the horn, lamps and gears. |
| HELP | The quick guide (it also opens by itself the first time you use each design). Click above the dashboard to close it. |
| X | Closes the dashboard. World > Car Dashboard, or the car icon, brings it back. |
Driving with the mouse
- Drag the steering wheel (the handlebars on the bike) and hold the BRAKE and ACCEL pedals (THROTTLE on the bike).
- The lamp row: < and > are the indicators, LAMPS steps through off, dipped and main beam (it reads MAIN on main beam), HAZ the hazard lights, P the handbrake, CRZ cruise control and HORN the horn. Hover any of them to see its key.
- The keys work as always: Up or W, Down or S, Left and Right, Page Up and Page Down.
Gears
- Car (8 gears) and truck (12): the button over the lever picks MANUAL (the default) or AUTO, remembered for each design.
- MANUAL: Page Up or + is a gear up, Page Down or − a gear down. Past top gear you stay in top; below 1 is N, then R. You sit down in N.
- AUTO: the car’s lever is P R N D and the truck’s R N A; the box picks the gear (D or A), and + or − take one yourself (M). Click D or A to hand it back. The truck shows its range (LOW / HIGH) and split.
- Bike: sequential, 1 N 2 3 4 5 6, with − and +.
- Every step sends the vehicle a Page Up or Page Down, just as the keys do, so gearbox scripts written for the keys work unchanged.
- The speed shown is the vehicle’s own. The revs and gear come from the vehicle’s script when it sends them, and from the viewer’s own model of that design when it does not.

Wheels, pedals and keys
Open Driving Controls from the dashboard’s CONTROLS button or World > Driving Controls. Whatever you drive with, a wheel, a gamepad or the keyboard, the vehicle receives the same controls the keys send, so every vehicle works with it.
A steering wheel, pedals or a gamepad
- Plug it in. In WolfViewer, choose and enable it in Joystick Configuration (the button at the top of Driving Controls). In WolfStorm, press any button on it: browsers only show a controller after a button press.
- For each control (steering, accelerator, brake and an optional clutch) press Detect and move it. The axis is picked for you, and the bar shows what is read.
- Tick “Drive with this controller whenever I sit on anything”. It then stops moving your avatar and the flycam.
- Each control has a tick box to turn it the other way round, and each pedal one for whether it rests at one end of its travel or in the middle.
- Combined pedals: one axis, accelerator one way from the middle and brake the other.
- Dead zone: how far the wheel or a pedal moves before it counts. Raise it if the vehicle creeps or turns by itself.
Horn, lamps and gears: your keys
Every action has a key (Set key; Escape cancels, Backspace removes it), a controller button (Detect) and a choice of what it sends the vehicle: nothing (only the dashboard lamp and the scripting bit), a Page Up or Page Down tap, or a chat command on a channel. Reset puts them all back. The keys you start with:
| Action | Key to start with | Sends the vehicle |
|---|---|---|
| Gear up | none (Page Up already does it) | Page Up |
| Gear down | none (Page Down already does it) | Page Down |
| Horn | H | nothing: the built-in horn plays |
| Lights | L | nothing |
| Left indicator | Z | nothing |
| Right indicator | X | nothing |
| Handbrake | B | nothing |
| Hazard lights | V | nothing |
| Cruise control | K | nothing |
The built-in horns
With nothing set for Horn, pressing it plays the horn for the design you are using, from the vehicle, so everyone near hears it: a 1.8 second double beep for the car, a 1.6 second air horn for the truck, a 0.8 second horn for the bike. You can sound it twice in a row, then once every 2 seconds. A vehicle with a horn of its own: set Horn to send that vehicle’s chat command instead.
Scripting
Two functions, for vehicle makers. wolfDriveInput gives your script exactly how far the driver turns the wheel and presses the pedals; wolfDashboard puts your vehicle’s own readings on their dashboard. Both work only:
- for a script in the linkset the driver is sitting on;
- on Wolf Territories regions, and for drivers using WolfViewer or WolfStorm.
Other viewers only ever send keys, so keep a control() event as well. When a call is refused it returns an empty list or FALSE, and wolfGetLastError() says why.
list wolfDriveInput(key avatar)
Your script must hold PERMISSION_TAKE_CONTROLS from the driver, as control() needs. The viewer sends its controls when they change (at most 10 a second) and once a second when they do not, so an age over about 2 seconds means the viewer has gone. The list is empty unless that driver sits on this object and their Wolf viewer has sent controls since they sat down.
| Index | Value | Type | Range |
|---|---|---|---|
| 0 | steer | float | -1 to 1, right is + |
| 1 | throttle | float | 0 to 1 |
| 2 | brake | float | 0 to 1 |
| 3 | clutch | float | 0 to 1 |
| 4 | gear | integer | WOLF_DRIVE_GEAR_P, _R, _N or _D, or 1 to 18 (a gear the driver chose) |
| 5 | buttons | integer | WOLF_DRIVE_BTN_* bits for the buttons held now |
| 6 | age | float | seconds since the viewer sent these values |
The constants
| Constant | Value | Meaning |
|---|---|---|
| WOLF_DRIVE_BTN_GEAR_UP | 1 | Held: gear up |
| WOLF_DRIVE_BTN_GEAR_DOWN | 2 | Held: gear down |
| WOLF_DRIVE_BTN_HORN | 4 | Held: horn |
| WOLF_DRIVE_BTN_LIGHTS | 8 | Held: lights |
| WOLF_DRIVE_BTN_INDICATOR_LEFT | 16 | Held: indicator left |
| WOLF_DRIVE_BTN_INDICATOR_RIGHT | 32 | Held: indicator right |
| WOLF_DRIVE_BTN_HANDBRAKE | 64 | Held: handbrake |
| WOLF_DRIVE_BTN_HAZARDS | 128 | Held: hazards |
| WOLF_DRIVE_BTN_CRUISE | 256 | Held: cruise |
| WOLF_DRIVE_GEAR_P | -2 | The lever is in P |
| WOLF_DRIVE_GEAR_R | -1 | The lever is in R |
| WOLF_DRIVE_GEAR_N | 0 | The lever is in N |
| WOLF_DRIVE_GEAR_D | 99 | The lever is in D |
A button bit is set while it is held, so act on the press: pressed = buttons & ~previous, as the example below does.
integer wolfDashboard(key avatar, list rules)
Key/value pairs, any order, any subset. Numbers outside a range are held to it; an unknown key, a key given twice, or a value that is not allowed refuses the whole call. Every value you send is kept while the driver sits in that vehicle, until you send "clear", 1. The speed is always measured by the viewer. The revs and the gear count as live while your script has sent something in the last 5 seconds; after that the viewer’s own model takes over again. At most 5 updates a second per driver (10 in a burst).
| Key | Type | Allowed values | Note |
|---|---|---|---|
| type | string | "car", "truck" or "bike" | |
| units | string | "kmh" or "mph" | |
| gear | string | "P", "R", "N", "D", "S", "C", "R1" to "R4", or "1" to "18" | |
| rpm | integer | 0 to 30000 (whole number) | |
| max_rpm | integer | 1000 to 30000 (whole number) | |
| redline | integer | 500 to 30000 (whole number) | |
| max_speed | integer | 10 to 1000 (whole number) | full scale, in units |
| fuel | float or integer | 0 to 100 | percent |
| adblue | float or integer | 0 to 100 | percent |
| temp | float or integer | -40 to 150 | coolant, degrees C |
| air1 | float or integer | 0 to 12 | brake circuit 1, bar |
| air2 | float or integer | 0 to 12 | brake circuit 2, bar |
| indicators | integer | 0 to 3 (whole number) | 0 off, 1 left, 2 right, 3 hazard |
| lights | integer | 0 to 2 (whole number) | 0 off, 1 dipped, 2 main beam |
| handbrake | integer | 0 to 1 (whole number) | |
| retarder | integer | 0 to 5 (whole number) | 0 off, 1..5 the script's own stages |
| cruise | integer | 0 to 1 (whole number) | |
| drive_time | integer | 0 to 86400 (whole number) | seconds driven since the last break |
| odo | float or integer | 0 to 9999999 | km |
| warnings | string | a comma-separated list of: engine, oil, battery, brake, abs, temp, tyre, airbag, seatbelt, fuel, adblue, air, door, esp ("" = none) | |
| clear | integer | 0 to 1 (whole number) | 1: forget every value this vehicle set |
This table is generated from the region software’s own list of accepted keys.
From the dashboard's own help
wolfDashboard(llAvatarOnSitTarget(), ["type", "car",
"rpm", 3200, "gear", "3", "fuel", 74]);A complete car
A simple car that drives from a real wheel and pedals (or a gamepad) with proportional throttle and steering, falls back to the keys for other viewers, and drives the dashboard: revs, gear, fuel, temperature, lamps, indicators, handbrake and a low-fuel warning. Put it in the root prim of a car-shaped linkset and sit in it. A sound called “horn” in the same prim plays on the horn button.
The analogue car script (analogue_car.lsl, 208 lines: show or hide)
// Wolf Territories example - ANALOGUE CAR. A simple car that drives from a real steering wheel
// and pedals, or a gamepad, with proportional throttle and steering, and drives the driver's Wolf
// dashboard (speedometer, rev counter, gears, fuel, lamps).
//
// wolfDriveInput(driver) -> [steer, throttle, brake, clutch, gear, buttons, age]
// steer -1..1 (right +), pedals 0..1, gear WOLF_DRIVE_GEAR_* or 1..18,
// buttons WOLF_DRIVE_BTN_* bits, age = seconds since the viewer sent it.
// An empty list from any other viewer (or Firestorm): this script then
// drives from the keys, through control(), as every car does.
// wolfDashboard(driver, [...]) -> the dashboard's rev counter, gear, fuel and lamps. The speed is
// the car's own; the viewer measures it.
//
// Both work only for a script in the linkset the driver is sitting on, and only on Wolf Territories
// regions (WolfSim). Put this in the root prim of a car-shaped linkset and sit in it. A sound called
// "horn" in the same prim plays on the horn button.
float MAX_SPEED = 30.0; // m/s at full throttle in D
float REVERSE_SPEED = 6.0; // m/s at full throttle in R
float MAX_TURN = 2.0; // rad/s at full lock
float TICK = 0.1; // seconds between control updates
integer DASH_EVERY = 3; // ticks between dashboard updates (the region allows 5 a second)
float LIVE_AGE = 2.0; // analogue values older than this mean the viewer has gone
// This car's own six-speed automatic, for its rev counter: the speeds (m/s) where it changes up.
list SHIFT_UP = [7.0, 12.0, 17.0, 22.0, 27.0];
float IDLE_RPM = 800.0;
float SHIFT_RPM = 6200.0;
key gDriver;
integer gKeys; // the held keys (control() levels), for viewers that send no analogue values
integer gTick;
integer gPrevButtons;
integer gLights; // 0 off, 1 dipped, 2 main beam
integer gIndicators; // 0 off, 1 left, 2 right
integer gHandbrake;
float gFuel = 100.0; // percent
setupVehicle()
{
llSetVehicleType(VEHICLE_TYPE_CAR);
llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_TIMESCALE, 1.0);
llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE, 0.2);
llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_TIMESCALE, 0.2);
llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, 0.2);
llSetVehicleVectorParam(VEHICLE_LINEAR_FRICTION_TIMESCALE, <100.0, 1.0, 1000.0>);
llSetVehicleVectorParam(VEHICLE_ANGULAR_FRICTION_TIMESCALE, <10.0, 10.0, 1000.0>);
llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, 1.0);
llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, 1.0);
}
// This car's gear for a speed (1..6), and its engine speed in that gear.
integer gearFor(float speed)
{
integer g = 1;
integer i;
for (i = 0; i < llGetListLength(SHIFT_UP); ++i)
{
if (speed > llList2Float(SHIFT_UP, i)) g = i + 2;
}
return g;
}
float rpmFor(float speed, integer g, float throttle)
{
float lo = 0.0;
float hi = llList2Float(SHIFT_UP, 0);
if (g > 1) lo = llList2Float(SHIFT_UP, g - 2);
if (g <= llGetListLength(SHIFT_UP)) hi = llList2Float(SHIFT_UP, g - 1);
else hi = MAX_SPEED;
float frac = (speed - lo) / (hi - lo);
if (frac < 0.0) frac = 0.0;
if (frac > 1.0) frac = 1.0;
float rpm = 2200.0 + frac * (SHIFT_RPM - 2200.0);
float revving = IDLE_RPM + throttle * 2000.0; // pulling away, the clutch slips
if (rpm < revving) rpm = revving;
return rpm;
}
// The lamp buttons work on the press, not while held.
pressButtons(integer buttons)
{
integer pressed = buttons & ~gPrevButtons;
gPrevButtons = buttons;
if (pressed & WOLF_DRIVE_BTN_LIGHTS) gLights = (gLights + 1) % 3;
if (pressed & WOLF_DRIVE_BTN_INDICATOR_LEFT) { if (gIndicators == 1) gIndicators = 0; else gIndicators = 1; }
if (pressed & WOLF_DRIVE_BTN_INDICATOR_RIGHT) { if (gIndicators == 2) gIndicators = 0; else gIndicators = 2; }
if (pressed & WOLF_DRIVE_BTN_HANDBRAKE) gHandbrake = !gHandbrake;
if ((pressed & WOLF_DRIVE_BTN_HORN) && llGetInventoryType("horn") == INVENTORY_SOUND) llTriggerSound("horn", 1.0);
}
drive()
{
float steer;
float throttle;
float brake;
integer gear = WOLF_DRIVE_GEAR_D;
list wheel = wolfDriveInput(gDriver);
if (llGetListLength(wheel) == 7 && llList2Float(wheel, 6) < LIVE_AGE)
{
// A Wolf viewer: exactly how far the wheel is turned and the pedals are pressed.
steer = llList2Float(wheel, 0);
throttle = llList2Float(wheel, 1);
brake = llList2Float(wheel, 2);
gear = llList2Integer(wheel, 4);
pressButtons(llList2Integer(wheel, 5));
}
else
{
// Any other viewer: the keys, all or nothing. Back is reverse, as on most SL cars.
if (gKeys & CONTROL_FWD) throttle = 1.0;
if (gKeys & CONTROL_BACK) { throttle = 1.0; gear = WOLF_DRIVE_GEAR_R; }
if (gKeys & (CONTROL_ROT_RIGHT | CONTROL_RIGHT)) steer += 1.0;
if (gKeys & (CONTROL_ROT_LEFT | CONTROL_LEFT)) steer -= 1.0;
}
float target;
if (gHandbrake || gear == WOLF_DRIVE_GEAR_P || gear == WOLF_DRIVE_GEAR_N) target = 0.0;
else if (gear == WOLF_DRIVE_GEAR_R) target = -REVERSE_SPEED * throttle;
else target = MAX_SPEED * throttle;
target = target * (1.0 - brake);
llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <target, 0.0, 0.0>);
// a right turn (steer +) is clockwise seen from above: negative about z
llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, <0.0, 0.0, -steer * MAX_TURN>);
vector vel = llGetVel();
float speed = llVecMag(<vel.x, vel.y, 0.0>);
gFuel -= speed * TICK / 1000.0 / 5.0; // 5 km per percent: this car's own figure
if (gFuel < 0.0) gFuel = 0.0;
if (++gTick % DASH_EVERY == 0)
{
integer g = gearFor(speed);
string label = (string)g;
if (gear == WOLF_DRIVE_GEAR_R) label = "R";
else if (gear == WOLF_DRIVE_GEAR_N) label = "N";
else if (gear == WOLF_DRIVE_GEAR_P) label = "P";
else if (gear >= 1 && gear <= 18) label = (string)gear; // the driver's own gear (paddles)
float rpm = IDLE_RPM + throttle * 2500.0;
if (label != "R" && label != "N" && label != "P") rpm = rpmFor(speed, g, throttle);
string warnings = "";
if (gFuel < 10.0) warnings = "fuel";
wolfDashboard(gDriver, [
"type", "car",
"rpm", (integer)rpm,
"gear", label,
"fuel", gFuel,
"temp", 90.0,
"lights", gLights,
"indicators", gIndicators,
"handbrake", gHandbrake,
"warnings", warnings]);
}
}
default
{
state_entry()
{
llSitTarget(<0.2, 0.0, 0.45>, ZERO_ROTATION);
llSetSitText("Drive");
setupVehicle();
llSetStatus(STATUS_PHYSICS, FALSE);
}
changed(integer change)
{
if (!(change & CHANGED_LINK)) return;
key av = llAvatarOnSitTarget();
if (av != NULL_KEY && gDriver == NULL_KEY)
{
gDriver = av;
llRequestPermissions(av, PERMISSION_TAKE_CONTROLS);
}
else if (av == NULL_KEY && gDriver != NULL_KEY)
{
gDriver = NULL_KEY;
gKeys = 0;
gPrevButtons = 0;
llSetTimerEvent(0.0);
llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, ZERO_VECTOR);
llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, ZERO_VECTOR);
llSetStatus(STATUS_PHYSICS, FALSE);
llReleaseControls();
}
}
run_time_permissions(integer perm)
{
if (!(perm & PERMISSION_TAKE_CONTROLS)) return;
llTakeControls(CONTROL_FWD | CONTROL_BACK | CONTROL_LEFT | CONTROL_RIGHT
| CONTROL_ROT_LEFT | CONTROL_ROT_RIGHT | CONTROL_UP | CONTROL_DOWN, TRUE, FALSE);
llSetStatus(STATUS_PHYSICS, TRUE);
gTick = 0;
llSetTimerEvent(TICK);
}
control(key id, integer levels, integer edges)
{
gKeys = levels;
}
timer()
{
if (gDriver != NULL_KEY) drive();
}
}
Customising
Everything below is a key of wolfDashboard, so a vehicle’s script decides how its dashboard looks. Send the fixed values once when the driver sits down, then only what changes.
| To change | Send | Notes |
|---|---|---|
| The design | "type", "car" | "truck" | "bike" | Switches the driver's dashboard to that design while they sit in your vehicle. |
| The units | "units", "kmh" | "mph" | Otherwise the driver's own KM/H or MPH choice is used. |
| The speedometer's scale | "max_speed", 10 to 1000 | Full scale, in the units shown. |
| The rev counter | "max_rpm", 1000 to 30000 and "redline", 500 to 30000 | The redline is never drawn past max_rpm. |
| Revs and gear | "rpm", 0 to 30000 and "gear", "P" "R" "N" "D" "S" "C" "R1".."R4" "1".."18" | Live while you keep sending them (within 5 seconds). |
| Fuel and temperature | "fuel", 0 to 100 (%) and "temp", -40 to 150 (degrees C) | |
| Lamps | "lights" 0 off, 1 dipped, 2 main; "indicators" 0 off, 1 left, 2 right, 3 hazard; "handbrake" 0/1; "cruise" 0/1 | |
| Truck readings | "adblue" 0-100 (%), "air1" and "air2" 0-12 (bar), "retarder" 0 off or 1-5, "drive_time" seconds since the last break | The Truck design shows these. |
| The odometer | "odo", kilometres | |
| Warning lamps | "warnings", "oil,abs" ("" for none) | See the list below. |
| Start again | "clear", 1 | Forgets every value this vehicle set. |
Warning lamps
Each name in warnings lights its own lamp, in the colours of the ISO 2575 standard: red means act now, amber means take care.
| Name | Lamp reads | Colour |
|---|---|---|
| engine | ENGINE | amber |
| oil | OIL | red |
| battery | BATT | red |
| brake | BRAKE | red |
| abs | ABS | amber |
| temp | TEMP | red |
| tyre | TYRE | amber |
| airbag | AIRBAG | red |
| seatbelt | BELT | red |
| fuel | FUEL | amber |
| adblue | AdBlue | amber |
| air | AIR | red |
| door | DOOR | red |
| esp | ESP | amber |
A truck, using only the keys above
// A truck: the Truck design, air pressure building up, the retarder on stage 2,
// 3 hours 10 minutes since the last break, and a low AdBlue warning.
wolfDashboard(driver, ["type", "truck", "rpm", 1350, "gear", "8",
"air1", 7.5, "air2", 7.2, "retarder", 2, "drive_time", 11400,
"adblue", 8, "warnings", "adblue"]);For the driver
- Your design, units, PANEL choice and the manual or automatic box are remembered.
- The dashboard opening by itself is on to start with. In WolfViewer it is the
WolfDashboardAutodebug setting.