In each 3D object you can add scripts that run and make the object alive.
To create a script :
- edit an object (Object > Edit), go in tab "Scripts" and click "Add".
- select the line "1 SCR Script" and click "Edit"
- write your script in the editor and click button "Apply".
In the script list, * denotes a compilation error, and ! denotes a runtime error.
Click the button show_error in the editor to display any runtime error details.
The Planet script language is a simple derivative of the C-family.
Data types include : bool, int, float, array, struct, and string(N) with N in 0 .. 1024.
A script is composed of : const, global variables, typedef, functions, and event handlers.
Functions and event handlers may contain const, typedef and local variables.
Function parameters can have mode 'in' (per default), 'ref', or 'out'.
In case a function parameter or function return type is string, it must appear without maximum length specification.
Control statements include : if, switch, for, while, break, continue, assert, abort, clear (zeroes variables).
Constants/values of array/struct can appear as aggregates, ex: {1, 2, i}
Operators include unary: + - ! ~ -- ++ and binary: * / % + - << >> == != < > <= >= && || & | ^
A typical script is supposed to handle short events from the Planet system, like opening a door when the user clicks on it.
If your script executes a very large number of instructions per day, this is not normal. Planet will penalize it by slowing it down.
A script that executes a lot of instructions per day is probably badly written:
- either it goes round in infinite loops,
- or it executes timer events with too short durations during the whole day,
- or it receives a large amount of messages from other scripts.
We encourage you to check the instruction consumption of your scripts via the Tools > Scripts menu. Check the column 'CPU Usage' : if it shows more than 1,000 units, there may be a problem. If it is over 10.000 units, there are certainly improvements to be made or bugs to be fixed. You can place say() statements for example in the event timer to check when it is triggered.
While the Tools > Scripts window is open, red bubbles rise above an object when a script changes its position or appearance.
Too many red bubbles indicate a poorly written script that sends its commands one after the other
instead of using Move Batches as explained in chapter 4.22.
Move Batches are highly recommended because they do not consume server CPU nor network traffic while executing.
In addition, they allow for smooth, shake-free movements.
When the script is compiled, or the object is taken from inventory or worn, the script is completely reinitialized. The START event is then executed first.
event start () { say ("hi, i'm starting !"); }
When the user clicks on the object with the left mouse button, the TOUCH event is executed.
event touch () { key k = touched_avatar(); int mesh_nr = touched_mesh_nr(); world_position wp = touched_world_position(); vector v = touched_mesh_position(); say ("touched avatar = " + itos(k[0]) + "," + itos(k[1]) + "," + itos(k[2]) + "," + itos(k[3])); say ("touched mesh_nr = " + itos(mesh_nr)); say ("touched world position = " + itos(wp.x) + "," + itos(wp.y) + "," + itos(wp.z)); say ("touched mesh position = " + ftos(v.x) + "," + ftos(v.y) + "," + ftos(v.z)); }When treating a touch event, the following functions can be called :
// returns a unique permanent key denoting the avatar that touched the object key touched_avatar (); // returns the touched mesh number (1 to 32) int touched_mesh_nr (); // returns the touch position in absolute world coordinates (see below) world_position touched_world_position (); // returns the touch position relative to the mesh center vector (see below) vector touched_mesh_position ();
The following data types are predefined :
typedef int[4] key; // key is a unique key identifying an avatar in the Planet system struct world_position // a position on the planet { int x, y, z; // coordinates in 1/256 mm } struct vector // a small position or rotation { float x, y, z; // coordinates in m }
The function same_key() can be used to check if two keys are identical :
bool same_key (key k1, key k2);
The function is_null_key() can be used to check if a key is null :
bool is_null_key (key k);
Event COLLISION is executed when an avatar collides with the object.
// avatar collided with scripted object. event collision() { key k = collision_avatar(); int nr = collision_mesh_nr(); vector n = collision_normal(); say (avatar_name(k) + " collides with mesh nr " + itos(nr) + " normal " + ftos(n.x) + " " + ftos(n.y) + " " + ftos(n.z)); }
The following functions can be called within an event COLLISION :
key collision_avatar(); // avatar who collided int collision_mesh_nr(); // mesh number that collided vector collision_normal(); // avatar to object normal vector
Objects having matter COLLISION have no physics (like matter PHANTOM) but they generate an event collision. They can be used as sensor to detect an arriving avatar.
Placing several objects in COLLISION material that overlap is not a good idea, because only one of them (at random) will trigger a collision event. You will then have the impression that this event is unreliable because it will not be triggered every time on the same object.
When an avatar writes a chat line, a nearby object receives the line it its event LISTEN.
// object heard an avatar talk event listen (key avatar, string message) { say (avatar_name(avatar) + " said " + message); }
Note that listeners in moving objects should be avoided, they do not work reliably.
Default range is 50m but that can be changed with set_listen_range() :
void set_listen_range (float range); // set range 0 to 50m, default is 50m.
When not in use, it is good practice to set the range to 0.0 to reduce server cpu.
To save also server cpu, you can set a filter to capture only some chat messages :
void set_listen_filter (string filter);Default filter is "*" to capture all messages.
Example: filter "!*" will capture only chat lines starting with "!", like "!start" and "!stop".
Each script can start maximum 16 timers (nr from 0 to 15) with different durations.
When a timer expires, the event TIMER is executed with the timer number that expired.
event start () { start_timer (nr => 0, seconds => 3.0); } // this event is executed when a timer expires event timer (int nr) // nr is timer number { say ("timer number " + itos(nr) + " expired"); }
Periodical timers can be created by restarting the timer each time after it expired, however this produces lag so it should be used as rarely as possible.
Example:
event start () { start_timer (nr => 0, seconds => 0.0); } // this event is executed when a timer expires event timer (int nr) // nr is timer number { say ("hi !"); start_timer (nr => 0, seconds => 3.0); // repeat after 3 seconds }
Scripts can send messages to one another with send_message or broadcast_message.
void send_message (int object_id, string message); void broadcast_message (string script_name, string message);
Sending example:
event touch() { send_message (object_id => 235, message => "hello to all scripts of object 235"); broadcast_message (script_name => "script1", message => "hello to all scripts named script1 on the planet"); }
The event message_received is executed when our script receives a message from another script.
event message_received (int sender_object_id, string message) { say ("received : " + message + " from " + itos(sender_object_id)); }
The sender_object_owner() function returns the owner of the object that sent us the message.
key sender_object_owner(); // query the owner of the object who sent us a message
See chapter "Inter-planet communication" to send messages between scripts on different servers.
The event server_restart is called when the planet server was just started.
event server_restart() { say ("hi, the planet server just started"); }
A script can use this event to reprocess any clock-dependant computations.
void say (string value);
Display text on chat within a range of 20m
// Example: event start () { say ("hi, i'm starting !"); }
void say_to (key avatar, string value);
Same as say but for a single avatar.
The chr(0,i) codes are used to display icons, replace i by a number.
event touch () { string(32) s; int i; s = ""; for (i=0; i<16; i++) s = s + chr(0,i); say ("icons : " + s); }
You can display an image on the chat by placing it in the script folder.
event touch () { // needs a texture "sun" in the object's script folder say ("this is my sun : " + image ("sun") + " :)"); }
The codes chr(1,i) change the font, chr(2,i) change the writing style, and chr(4,i,j) change the color, replace i and j with numbers.
// greeter string font(int f) { return chr(1, f); } string style(bool underlined, bool italic, bool bold) { int s=0; if (underlined) s++; if (italic) s+=2; if (bold) s+=4; return chr(2, s); } string color(int col) { return chr(4, col & 0xFFFF, col>>16); } event touch () { say ("big " + color(0x8080FF) + "kiss" + font(9) + color(0x00FF00) + style(underlined => true, italic => true, bold => true) + " from Didi"); }
void set_mesh_active (int mesh_nr, bool enable);
Makes mesh active or inactive.
Inactive meshes are invisible and cause no avatar collisions.
Example:
event start () { set_mesh_active (mesh_nr => 1, enable => false); // make mesh 1 inactive set_mesh_active (mesh_nr => 2, enable => true); // make mesh 2 active }
void set_mesh_position (int mesh_nr, vector position);
Moves mesh within an object (range -32.768 to +32.767 m)
The position is given as a vector in x,y,z coordinates.
Example:
event start () { set_mesh_position (mesh_nr => 1, position => {1.299, -0.893, 0.5}); }
void set_mesh_rotation (int mesh_nr, vector rotation);
Turns a mesh within an object.
The rotation is given as x,y,z angles in degrees (-360.0 to +360.0)
The rotation axis is the center 0,0,0 of the mesh.
Example:
event start () { set_mesh_rotation (mesh_nr => 1, rotation => {0.0, 0.0, 45.0}); }
void set_mesh_color (int mesh_nr, int color);
Changes mesh color
Color is defined as hex RGB value (0xBBGGRR)
Example:
event start () { set_mesh_color (mesh_nr => 1, color => 0xFFC0D0); }
void set_mesh_transparency (int mesh_nr, float transparency);
Changes mesh transparency.
The transparency value must be between 0.0 and 1.0
Example:
event start () { set_mesh_transparency (mesh_nr => 1, transparency => 0.3); }
void set_mesh_light (int mesh_nr, int color, float attenuation, // between 0.0 and 1.0 float range, // between 0.0 and 65.0 int cone); // 0=point light, or spot size between 1 and 255.
Defines a point or spot light at coordinate 0,0,0 of the mesh.
To disable the light, call this function with range 0.0
Example:
event start () { set_mesh_light (mesh_nr => 1, color => 0xFFFFFF, attenuation => 0.6, range => 12.0, cone => 0); }
void set_mesh_lightning (int mesh_nr, bool ambiant, // true = daylight enlightens the mesh bool sunlight); // true = sun enlightens the mesh
Allows to remove the daylight or the sun that enlightens a mesh, for example if it's in a basement.
Example:
event start () { set_mesh_lightning (mesh_nr => 1, ambiant => false, sunlight => false); }
void set_mesh_glow (int mesh_nr, int color);
Allows an object to shine in the dark.
Example:
event start () { set_mesh_glow (mesh_nr => 1, color => 0x0000FF); }
void set_mesh_uv (int mesh_nr, int mode, float u = 0.0, float v = 0.0, bool ping_pong = false, bool one_shot = false, bool perlin = false);
Make all textures of this mesh move by changing the UV dynamically.
There are 6 modes :
// mode 0 : turn uv off set_mesh_uv (mesh_nr => 1, mode => 0); // mode 1 : set static U,V offset set_mesh_uv (mesh_nr => 1, mode => 1, u => 0.5, v => 0.3); // mode 2 : set sliding U,V offset // u, v denote the speed of sliding set_mesh_uv (mesh_nr => 1, mode => 2, u => 0.1, v => 0.3); // mode 3 : set frames // the texture must consist of N images of same size, disposed vertically. // The successive images are shown like in a diaporama. // u denotes the number of images, and v denotes the speed of change // optional parameter ping_pong indicates if we want to show the images backwards again when arriving at the end. // optional parameter one_shot indicates if we want to show all images only once, or repeat forever. set_mesh_uv (mesh_nr => 1, mode => 3, u => 3.0, v => 100.0); set_mesh_uv (mesh_nr => 1, mode => 3, u => 3.0, v => 100.0, ping_pong => true, one_shot => true); // mode 4 : rotating texture // u denotes the maximum angle of rotation (360.0 for a full circle). // v denotes the rotation speed. // optional parameter ping_pong indicates if we want to rotate back when arriving at the end. // rotation occurs at u,v = 0,0 so it a centered rotation is wished // you should set the texture u,v in range -0.5 to +0.5 when editing the mesh. set_mesh_uv (mesh_nr => 1, mode => 4, u => 360.0, v => 10.0); set_mesh_uv (mesh_nr => 1, mode => 4, u => 45.0, v => 80.0, ping_pong => true); // mode 5 : pulse texture // u denotes the pulse amplitude // v denotes the speed. // optional parameter ping_pong indicates if we want a back-and-forth movement set_mesh_uv (mesh_nr => 1, mode => 5, u => 0.1, v => 100.0); set_mesh_uv (mesh_nr => 1, mode => 5, u => 0.1, v => 100.0, ping_pong => true); Finally, option 'perlin' can be enabled for horizontal water textures.
void set_mesh_texture (int mesh_nr, string texture);
Remplaces the texture of a whole mesh by a new temporary texture.
The new texture must be copied in the object's scripts folder.
An empty texture name "" will restore the original texture.
Likewise, if vous rezz the object on the land, it will receive again its original texture.
Example:
event start () { set_mesh_texture (mesh_nr => 1, texture => "checkboard"); }
int object_id();
returns the object's ID. This is a number that identifies the object on this Planet server until the object is deleted.
bool is_worn ();returns true if the current object is worn, false if it's created on land.
string object_name ([int object_id]);
returns object's name (max 32 characters)
void set_object_name (string name);for a worn object, temporarily changes the object's name, so that say() calls use a different name.
key object_owner ([int object_id]);
returns object's owner.
string object_owner_date ([int object_id]);
returns a date in format "YYYYMMDD"
int object_nb_meshes();
return object's number of meshes.
int domain_id();
return domain's id where the object is located.
string domain_name();
return domain's name where the object is located.
bool domain_adult();
test if the object is located on an adult domain.
int object_access();
return object's access rights, a sum of the following values :
RIGHT_IS_LOCKED = 1 RIGHT_ANYONE_CAN_MOVE = 2 RIGHT_ANYONE_CAN_BUY = 4 RIGHT_DISTRIBUTE_MONEY = 8 RIGHT_OWNER_CAN_SELL = 16 RIGHT_OWNER_CAN_MODIFY = 32 RIGHT_NEXT_OWNER_CAN_SELL = 64 RIGHT_NEXT_OWNER_CAN_MODIFY = 128 RIGHT_BUILDER_CAN_TAKE_COPY = 256 RIGHT_BUILDER_CAN_MODIFY = 512 RIGHT_BLOCK_SCRIPTS = 1024
You can test individual accesses with the operator &.
world_position object_world_position (int object_id);
returns object's world position.
vector object_rotation (int object_id);
returns object's rotation.
int set_object_world_position (int object_id, world_position position);moves object
returns 0 if OK, or one of the following negative values : -1 : bad object_id -2 : no move access rights on this object -3 : no rezz access rights on new area -4 : new area is full
You can move an object over sea, but it will be deleted
if it stays 1 hour on sea without any avatar watching it.
You cannot move an object different from the current object itself
if the script object is worn or was rezzed by script.
void set_object_rotation (int object_id, vector rotation);
rotates object
int rezz_object_relative (string item_name [, vector position [, vector rotation]]); int rezz_object_absolute (string item_name , world_position position [, vector rotation]);
deposits an object in the world, either at a relative position from the script object,
or at an absolute world position.
returns a positive value (id of the created object),
or a negative error (-1 = no rezz rights, -2 = area full)
int clone_object (bool active);
deposits a copy of the object running the script, in exactly the same place as the original object.
with active = true for an exact copy, or false for a copy with all meshes initially disabled so that it remains invisible.
returns a positive value (id of the object created), or a negative error (-1 = not allowed to rezzer, -2 = area full, -3 = not allowed for a worn object)
int parent_object_id ();returns a positive id of the parent object who rezzed, cloned or wore this object,
void delete_object();
deletes the object running this script.
If you rezz an object on land, and this object is deleted, then the parent object that rezzed it receives an event child_died with the object_id of the object that was deleted :
event child_died (int child_id) { }
Examples:
event touch () { say ("object id = " + itos(object_id())); say ("object name = " + object_name()); say ("domain name = " + domain_name()); } event touch () { world_position wp = object_world_position (object_id()); say ("world position = " + itos(wp.x) + "," + itos(wp.y) + "," + itos(wp.z)); } event touch() { vector v = object_rotation (object_id()); say ("rx = " + ftos(v.x)); say ("ry = " + ftos(v.y)); say ("rz = " + ftos(v.z)); } event touch() { say ("bye"); delete_object (); }
int next_object_of_area (int area_x, int area_y, ref int snr);list all objects of an area.
Example:
event touch() { int snr = 0; for (;;) { int object_id = next_object_of_area (area_x => 2, area_y => 3, ref snr); if (object_id == 0) break; say (itos(object_id)); } }
To move an object or a mesh, the naive way is to repeat commands several times per second. This however produces a shacking movement, uses a lot of CPU and generates a lot of traffic on the internet. In short, it creates lag.
The serious way is to use a move batch. To do this, you need to prepare a sequence of movements to be executed in advance. The sequence will be compressed and sent to the PC only once where it will be executed without disturbing the server. For example to open a door, you will make a batch that gives just the time of movement and the final rotation, and the PC will take care of generating all intermediate positions. The PC can even repeat your sequence a lot of times, imagine for example a fan.
Move Batches are highly recommended because they do not consume server CPU nor network traffic while executing. In addition, they allow for smooth, shake-free movements.
All commands of a batch must be enclosed between :
void begin_move (); void end_move ();
Inside a batch, you can specify one or more jobs, each one must start with :
void move_job (bool repeating = false, bool sync = false, int sync_delay = 0); repeating : true to repeat the job commands. sync : true to synchronize with other jobs of same total duration (for repeating=true only) sync_delay : a synchronization offset value in milliseconds (for sync=true only).
You can specify one or more of the following commands within a job :
void set_mesh_active (int mesh_nr, bool enable); void set_mesh_position (int mesh_nr, vector position); void set_mesh_rotation (int mesh_nr, vector rotation); void set_mesh_color (int mesh_nr, int color); void set_mesh_transparency (int mesh_nr, float transparency); void set_mesh_light (int mesh_nr, int color, float attenuation, float range); void set_mesh_lightning (int mesh_nr, bool ambiant, bool sunlight); void set_mesh_glow (int mesh_nr, int color); void set_mesh_uv (int mesh_nr, int mode, float u = 0.0, float v = 0.0, bool ping_pong = false, bool one_shot = false); void set_mesh_texture (int mesh_nr, string texture); int set_object_world_position (int object_id, world_position position); void set_object_rotation (int object_id, vector rotation);
When one of these commands is specified between begin_move() and end_move(), instead of executing the command immediately, it is recorded in the move batch. Once arrived at end_move(), the batch is closed, checked, compressed and sent from server to PC for execution.
Between commands, you can specify a duration to cause a fading between the former and later states with :
void job_duration (int duration); // duration must be >= 16 milliseconds
To stop a running batch, call :
void stop_move ();
Some rules :
. if you specify a direct command outside the batch, the server will first stop the batch.
. command set_object_world_position() can only be specified in the first job of a batch.
. a repeating job must have at least one command job_duration.
. a non-repetitive job cannot have a job_duration command at the end.
. batches are executed in order.
. a repeating batch will no longer repeat when another following batch is sent.
Further commands :
int end_move2 ();
Instead of end_move() that stops on an area error, you can also use end_move2() that returns 0 if OK or a negative error if the area cannot be crossed.
int nb_queued_moves ();You can query the number of queued batches in case several non-looping moves are pending.
float rest_move_duration ();
Returns the time it will take for a non-repetitive batch to stop, in seconds.
Here are some examples:
A turning fan ------------- // fan bool g_enabled; event touch () { g_enabled = !g_enabled; if (g_enabled) { begin_move (); move_job (repeating => true); set_mesh_rotation (mesh_nr => 1, rotation => {0.0, 0.0, 0.0}); job_duration (1000); set_mesh_rotation (mesh_nr => 1, rotation => {0.0, 0.0, 120.0}); job_duration (1000); set_mesh_rotation (mesh_nr => 1, rotation => {0.0, 0.0, 240.0}); job_duration (1000); end_move (); } else { stop_move(); } }
Rotation angles should be less than 180° apart to guarantee a deterministic path between two angles.
A smooth moving door -------------------- // door bool g_is_open; event touch() { float angle; g_is_open = !g_is_open; begin_move (); move_job (repeating => false); job_duration (1000); if (g_is_open) angle = 90.0; else angle = 0.0; set_mesh_rotation (mesh_nr => 1, rotation => {0.0, 0.0, angle}); end_move (); } Flying carpet ------------- // flying carpet bool g_on; event touch() { g_on = !g_on; if (g_on) { int id = object_id(); world_position wp = object_world_position (id); world_position wp2 = wp; int rc; wp2.z += 256*1000; wp2.x -= 256*65536; begin_move (); // first job : change object position between two points move_job (repeating => true); rc = set_object_world_position (id, wp); job_duration (100000); rc = set_object_world_position (id, wp2); job_duration (100000); // second job : some weird rotations move_job (repeating => true); set_mesh_rotation (mesh_nr => 1, rotation => {0.0, 0.0, 0.0}); job_duration (10000); set_mesh_rotation (mesh_nr => 1, rotation => {0.0, 20.0, 120.0}); job_duration (10000); set_mesh_rotation (mesh_nr => 1, rotation => {20.0, 0.0, 240.0}); job_duration (10000); end_move (); } else { stop_move (); } } Fading color object ------------------- // fading color object event start() { begin_move (); move_job (repeating => true); set_mesh_color (mesh_nr => 1,color => 0xFF); job_duration (6000); set_mesh_color (mesh_nr => 1,color => 0xFF00); job_duration (6000); set_mesh_color (mesh_nr => 1,color => 0xFF0000); job_duration (6000); end_move (); } Bouncing Cube ------------- // bouncing cube that changes color event start() { int i; begin_move (); // first job : bouncing position up and down move_job (repeating => true); for (i=0; i<10; i++) { float f = itof(i); f = 1.0 - f * f * 0.01; set_mesh_position (mesh_nr => 1, position => {0.0, 0.0, f}); job_duration (100); } for (i=8; i>0; i--) { float f = itof(i); f = 1.0 - f * f * 0.01; set_mesh_position (mesh_nr => 1, position => {0.0, 0.0, f}); job_duration (100); } // second job : changing rotation angles move_job (repeating => true); set_mesh_rotation (mesh_nr => 1, rotation => {0.0, 0.0, 0.0}); job_duration (1000); set_mesh_rotation (mesh_nr => 1, rotation => {30.0, 0.0, 90.0}); job_duration (1000); set_mesh_rotation (mesh_nr => 1, rotation => {0.0, 0.0, 180.0}); job_duration (1000); set_mesh_rotation (mesh_nr => 1, rotation => {0.0, 30.0, 270.0}); job_duration (1000); // third job : fading and changing color move_job (repeating => true); set_mesh_color (mesh_nr => 1,color => 0xFF); job_duration (2000); set_mesh_color (mesh_nr => 1,color => 0xFF00); job_duration (2000); set_mesh_color (mesh_nr => 1,color => 0xFF0000); job_duration (2000); end_move (); }
bool avatar_online (key k);
Returns true if an avatar is online, false if not.
string avatar_name (key k);
Returns an avatar current full name (maximum 71 characters).
int avatar_rank (key k);
Returns an avatar rank : -1=banned, 0=visitor, 1=resident, 2=member manager, 3=security officer, 4=senior builder, 5=domain manager, 6=land owner.
bool has_rank (key k);Returns true if the avatar is present in the members of the domain where the object is located, false otherwise.
void set_avatar_rank (key k, int rank);
Changes an avatar's rank, if you have rights for that.
int avatar_gender (key k);
Returns an avatar gender : 0=male, 1=female.
int avatar_adult (key k);
Returns an avatar's adult state : 0=non-adult, 1=adult, -1=invalid key.
int avatar_language (key k);
Returns avatar langage (0 = FRENCH, 1 = ENGLISH, 2 = GERMAN, -1 = unknown key)
int avatar_experience (key k);
Returns avatar experience, or -1 if avatar key is unknown.
int avatar_timezone (key k);
Returns avatar timezone, in hours, from -12 to +12.
string avatar_title (key k);
Returns avatar title, max 24 characters.
world_position avatar_world_position (key k);
Returns an avatar world position (z is 0 if standing on floor at altitude 0).
int avatar_z_rotation (key k);
Returns an avatar orientation, as follows :
0 = north, facing positive Y 90 = east, facing positive X -90 = west, facing negative X -180 or +180 = south, towards negative Y
Example:
event touch () { key k; bool online; string(71) name; int rank; int gender; world_position wp; int angle; k = touched_avatar(); online = avatar_online (k); name = avatar_name (k); rank = avatar_rank (k); gender = avatar_gender (k); wp = avatar_world_position (k); angle = avatar_z_rotation (k); say ("online = " + btos(online)); say ("name = " + name); say ("rank = " + itos(rank)); say ("gender = " + itos(gender)); say ("world pos = " + itos(wp.x) + "," + itos(wp.y) + "," + itos(wp.z)); say ("angle = " + itos(angle)); }
void set_avatar_world_position_and_angle (key k, world_position position, int angle);
Teleports an avatar.
Example:
event touch () { key k = touched_avatar(); world_position wp = touched_world_position(); set_avatar_world_position_and_angle (k, position => wp, angle => 0); }
void teleport_to_planet (key k, string url);
teleports an avatar to another planet server.
url must have the form "planet://37.59.48.75/domain4"
If specified, the domain must be visible in public search.
The script object must have at least rank security officer on the origin domain.
See also the teleport_to_planet2 command in chapter 21. Inter-planet communication.
key next_avatar (ref int snr);lists one by one all avatars in a radius of 256 meters.
Example:
event touch() { int snr = 0; for (;;) { key avatar = next_avatar (ref snr); if (snr == 0) break; say (avatar_name (avatar)); } }
event owner_login (bool in) { }
Event owner_login is called when the owner of the object logs in or out.
. it is used typically for a presence cube.
. it does not work in worn objects.
int avatars_online_count();
returns the number of online avatars on this planet (0 to 1024).
key avatar_key (string name);
returns the avatar key corresponding to the avatar name supplied. The name may be a little inaccurate, so the function will choose the closest name. A null key is returned if the avatar has not been found, which can be tested with is_null_key().
bool is_sitting (key avatar);
Tests if an avatar is sitting on this object.
bool sit (int mesh_nr, vector position, vector rotation, key avatar);Sits an avatar with position/rotation on this object's mesh_nr.
void unsit (key avatar);
Make an avatar stand up if it was sitting on this object and stops all animations that were started during the sitting.
void start_animation (string animation, key avatar); void stop_animation (string animation, key avatar);Starts or stops an animation.
bool is_animation_active (string animation, key avatar);
Tests if this animation currently runs on the given avatar.
void override_animation (int typ, string animation);override standard animations (stand, walk, run, fly, jump)
// Example 1 : dancing ball const string ANIMATION_NAME = "dancing"; event touch() { key k = touched_avatar(); if (is_animation_active (ANIMATION_NAME, k)) stop_animation (ANIMATION_NAME, k); else start_animation (ANIMATION_NAME, k); } // Example 2 : sit on a chair event touch() { key k = touched_avatar(); if (is_sitting (k)) { unsit (k); } else if (sit (mesh_nr => 1, position => {0.0, 0.0, 1.0}, rotation => {0.0, 0.0, 0.0}, avatar => k)) { start_animation ("sit", k); } }
event click_avatar() { key k1 = clicking_avatar(); // get key of avatar who clicks key k2 = clicked_avatar(); // get key of avatar who is clicked. say ("click " + avatar_name(k1) + " clicked on " + avatar_name(k2)); }
Event click_avatar() is generated when the user clicks on an avatar that is sitting on an object. All scripts of this object receives then this event. This can be used to change the avatar's animation.
The following functions are allowed inside an event click_avatar :
key clicking_avatar(); // get key of avatar who clicks key clicked_avatar(); // get key of avatar who is clicked.
It is possible that the avatar is not sitting on the object anymore if this event arrives late. You can check this with is_sitting().
bool get_sitter (out sitter);
Returns, in several calls, all the avatars sitting on the object.
Returns false if there are no more avatars left.
At each event, we start again at the first avatar.
All avatars sitting on an object can be listed like this :
sitter s; while (get_sitter (out s)) { say ("sitter : " + avatar_name(s.avatar)); say ("mesh_nr : " + itos(s.mesh_nr)); say ("pos : " + ftos(s.position.x) + " " + ftos(s.position.y) + " " + ftos(s.position.z)); }
The structure sitter is defined like this :
struct sitter { key avatar; int mesh_nr; vector position; vector rotation; }
This can be used for example for couple animations :
event touch() { key k = touched_avatar(); if (is_sitting (k)) // already sitting { unsit (k); // stand up } else { sitter s; if (get_sitter(out s) && s.mesh_nr == 1) { // someone is already sitting on mesh 1 if (sit (mesh_nr => 2, // sit on mesh 2 position => {0.0, 0.0, 1.0}, rotation => {0.0, 0.0, 0.0}, avatar => k)) { start_animation ("sit", k); } } else { if (sit (mesh_nr => 1, // sit on mesh 1 position => {1.0, 0.0, 1.0}, rotation => {0.0, 0.0, 0.0}, avatar => k)) { start_animation ("sit", k); } } } }
event avatar_unsits (key avatar) { }
Event avatar_unsits signals that an avatar unsits from an object.
It is called when a) another object calls sit() on the avatar,
or b) the avatar teleports away,
or c) the avatar disconnects.
It is not called when a) the object calls unsit() on the avatar,
or b) the sitting object is deleted,
or c) the planet server stops.
After sitting an avatar, you can set its camera stability.
void set_camera_stability (int stability, key avatar);The following three stability values are possible:
0 = STABLE (camera always horizontal) (this is the default after sitting) 1 = DYNAMIC (horizontal and vertical camera rotations allowed) 2 = UNRESTRICTED (camera follows the avatar, all camera rotations allowed, be careful makes sea sick)
Additionnal passengers can also sit on the vehicle and set their camera stability, but only one driver can call control_vehicle(); any previous drivers become passengers.
void control_vehicle (vehicle_parameters p, key avatar); struct vehicle_parameters { bool active; // true = behaves as vehicle, false = vehicle mode off //--------------------------------- // physics float mass; // 1000 kg float max_speed; // in km/h maximal speed vector dimensions; // vehicle dimensions (large, length, height) (0.6 to 32.767 meter) The vehicule's physik is modelled as a stretched bubble with these dimensions. int nb_wheels; // 1 (monocycle), 2 (bike), 3 (tricycle), or 4 (car) (1 to 4) Under the vehicle are wheels, modelled as compressible spheres, that push it upwards. The number of wheels has an influence on the balance of the vehicle. if the number of wheels is 1, it is a vehicle that always remains horizontal (monocycle) if the number of wheels is 2, it can be a bike (wheels one behind the other) if left_to_right_wheel_distance = 0 and axis_to_axis_distance > 0, or a segway (one wheel on the left and one on the right) if left_to_right_wheel_distance > 0 and axis_to_axis_distance = 0. if the number of wheels is 3, there is one wheel in front in the middle, and two wheels behind. if the number of wheels is 4, it is a classic car. The wheels are centered and disposed according to left_to_right_wheel_distance and axis_to_axis_distance. float tyre_radius; // 0.25 (0.001 to 32.767 meter) Radius of a wheel sphere, in meters. float left_to_right_wheel_distance; // (0.0 to 32.767 meter) Distance between the center of the left wheel sphere and the center of the right wheel sphere, in meters (0.0 to 32.767) you have to specify zero for a bike. float axis_to_axis_distance; // (0.0 to 32.767 meter) (use 0.0 for segway) Distance between the center of the front wheel sphere and the center of the rear wheel sphere, in meters (0.0 to 32.767) you have to specify zero for a segway. this influences the radius of the circle in which the vehicle turns (a long truck turns on a longer circle than a car) bool set_z_range; // true = vehicle only allowed in altitude range min_z to max_z, false = no restriction. if you want to limit allowed altitudes of the vehicule, you set set_z_range to true. float min_z; // (-8000.0 to 8000.0 meters) (set 0.0 for a ship) float max_z; // (-8000.0 to 8000.0 meters) (set 0.0 for a ship) Once set_z_range is true, you can set a range here, for example: set both min_z and max_z to 0.0 for a ship, so it's always on sea level. set min_z to 0.0 and max_z to 8000.0 for a hovercraft, so it cannot sink below sea level. set min_z to -8000.0 and max_z to 0.0 for a submarine so it cannot go above sea level. //--------------------------------- // keyboard configuration int key_direction; // turns wheels left/right default: 1 int key_engine; // moves vehicle forwards/backwards default: 2 int key_climb; // moves vehicle upwards/downwards (helicopter) int key_yaw; // turns vehicle (nose left/right) int key_pitch; // turns vehicle (nose up/down) int key_roll; // rolls vehicle (left ear up/down) The following key values are allowed : 0 = key not assigned 1 = cursor left/right 2 = cursor up/down 3 = page up/down 4 = ctrl+cursor left/right 5 = ctrl+cursor up/down 6 = ctrl+page up/down (you can use negative value to inverse the sense of the controls) //--------------------------------- // vehicle control float engine_force_on_road; // engine forward force when wheels touch ground (0.0 to 1.0e8) This is used for a car to give a forward force. set value 1.0 float engine_force_in_air; // engine forward force when wheels don't touch ground (0.0 to 1.0e8) This is used for a ship or a plane to give a forward force. set value 1.0 float climbing_force; // upwards force with key_climb (0.0 to 1.0e8) This is used for a helicopter/drone to give an upward force. set value 1.0 float yaw_force; // turn force with key_yaw (0.0 to 1.0e8) float pitch_force; // turn force with key_pitch (0.0 to 1.0e8) float roll_force; // turn force with key_roll (0.0 to 1.0e8) These 3 are used for ships or planes for turning in all directions. set value 1.0 bool yaw_dependant_on_forward; // true = yaw force depends on forward movement, false = not bool pitch_dependant_on_forward; // true = pitch force depends on forward movement, false = not bool roll_dependant_on_forward; // true = roll force depends on forward movement, false = not Set to true for harder control : you can only turn when you also move forward. float direction_factor; // how fast the wheels turn when pressing key (1.0) (0.0 to 1.0e8) float direction_max_angle; // max wheels angle (30.0 degrees) (0.0 to 90.0) Set how fast the user makes the wheel turn when pressing direction key, and what max angle the wheels can have. float yaw_factor; // how fast yaw rudder moves (0.0 to 1.0e8) float yaw_max_angle; // max yaw angle (30.0 degrees) (0.0 to 90.0) float pitch_factor; // how fast pitch rudder moves (0.0 to 1.0e8) float pitch_max_angle; // max pitch angle (30.0 degrees) (0.0 to 90.0) float roll_factor; // how fast roll rudder moves (0.0 to 1.0e8) float roll_max_angle; // max roll angle (30.0 degrees) (0.0 to 90.0) Set how fast the user makes the rudder or flaps turn when pressing keys, and what max angle the rudder/flaps can have. float sliding_coef; // (0.0 to 1.0) float sliding_z; // -0.05 (-32.767 to 32.767) negative z where wheels force applies, in meters sliding_coef indicates how slippy the tyres are (0.0 = asphalt to 1.0 = ice snow) sliding_z is a value in meter that indicates at which height the tyres force is applied to the ground, it can have 0.0 for total stability. A negative value like -0.05 can make the car turn over in curves. float air_friction_coef; // (0.0 to 1.0) float air_friction_vertical_coef; // (0.0 to 1.0) air_friction_coef indicates how dense the air/water is, for a ship/plane. a value of 0.0 will feel like in space (total inertia). For better control when turning you will want some like 0.5 air_friction_vertical_coef is usually 0.0 a value like 1.0 blocks vertical movement when not in vehicle forward direction. this can be used for a vehicule that flies strictly forward, like a plane, glider, deltaplane. float spring_force; // 1.3 shock absorbers force float spring_damping; // 0.005 shock absorbers counter-force (damping) These parameter control the wheel shock absorbers : the force and counter-force. float keel_on_road; // (0.0 to 1.0e8) float keel_in_air; // (0.0 to 1.0e8) These parameter work like a ship keel, adding weight under the car to incrase stability. The first parameter is used when the vehicle wheels touch ground, the second when not. float stability_in_air; // 0.01 (0.0 to 1.0) Slows down rotationnal speed, for a plane or a ship. Value 0.0 does nothing, so the vehicle will balance back and forth like a pendulum. A small value like 0.01 will slow down this. float yaw_z; // (0.0 to 1.0e8) z offset above center of mass where to apply directional force When a plane is turning using yaw, this will also roll the plane/ship a little in the direction of the turn. float forward_slowdown; // (-1.0 to 1.0) slows forward move of vehicle (-1.0 = no slowdown, 0.0 = slowdown of 0.5%, 1.0 = slowdown of 1%) float turning_slowdown; // (-1.0 to 1.0) slows turning of vehicle (-1.0 = no slowdown, 0.0 = slowdown of 0.5%, 1.0 = slowdown of 1%) //--------------------------------- // options bool can_fly; // true = cancels gravity when in the air or on sea, for flying, sailing vehicles true for vehicles that can stay in the air without falling, like planes, ships, submarines. false for cars, hovercrafts or anything that falls on the ground. bool apply_cubic_shape_in_air; // true = smooth turning when wheels not touching ground true is recommended for flying/sailing objects for easier keyboard rotation control. when in the air, the rectangular vehicule mass is ignored and replaced by a cube. false for cars bool block_fly_backwards; when true, you can't move backwards when wheels don't touch the ground. bool auto_unblock; // true when true, when vehicle is not moving and wheels don't touch the ground, it is supposed stuck. Then an automatic unblock resets rotations to zero. bool block_wheels_in_the_air; // stop the wheels of a plane when it's in the air when true, the mesh wheels stop turning when they don't touch the ground anymore (for a plane after take off) //--------------------------------- // mesh wheels display ROTATING_MESH rotating_mesh[2 .. 32]; mesh 1 is the vehicle and cannot be configured mesh 2 to 32 can be configured as wheels, rudder or other moving parts. for each mesh, you specify a type and a radius. the mesh numbers must be contiguous, i.e. don't leave holes. struct ROTATING_MESH { int typ; // type of wheel float radius; // in meters } the following types of wheels are possible: 0 = off 1 = front left wheel 2 = front center wheel 3 = front right wheel 4 = back left wheel 5 = back center wheel 6 = back right wheel 7 = segway left (or tank) 8 = segway right (or tank) 9 = car steering wheel, bike fourche (controlled by direction) (set radius to 1.0 !) 10 = ship rudder (controlled by yaw) (set radius to 1.0 !) 11 = height rudder (controlled by pitch) (set radius to 1.0 !) 12 = roll rudder (controlled by roll) (set radius to 1.0 !) The specified radius must match exactly the radius of the mesh wheels, in meters, so that the wheels turn with correct speed. vector mesh_rotation[2 .. 32]; for each mesh 2 to 32, you can specify a constant post-rotation. the vector indicates the (x, y, z) rotation in degrees. this is used for example to inclinate a bike front part by 20° float inclination_angle_direction; for a monocycle or a bike, max angle to inclinate the vehicule when turning in curves. float inclination_angle_height; for a monocycle or a segway, max angle to inclinate the vehicule when moving forward or back. //--------------------------------- }
For script examples, see the demo vehicles in the shopping center.
You can handle the event "vehicle_changed" for reacting to some actions :
event vehicle_changed (vehicle_change e) { if (e.forward) { say ("go !"); } if (e.backward) { say ("STOP"); } }
The structure "vehicle_change" is defined as :
struct vehicle_change { bool forward; // true if user pressed forward key to increase engine speed bool backward; // true if user pressed backward key to reduce engine speed bool left; // true if user turned left 25° bool right; // true if user turned right 25° }
Events collision_vehicle_avatar, collision_vehicle_vehicle and collision_vehicle_object are triggered when your vehicle collides with an avatar, another vehicle, or an object in matter COLLISION.
Example:
// in a vehicle event collision_vehicle_avatar () { key k = collision_avatar(); say ("collision_vehicle_avatar " + avatar_name(k) + " force = " + ftos(collision_force())); } // in a vehicle event collision_vehicle_vehicle () { key k = collision_avatar(); say ("collision_vehicle_vehicle " + avatar_name(k) + " force = " + ftos(collision_force())); } // in a vehicle or an object of matter COLLISION event collision_vehicle_object () { key k = collision_avatar(); float force = collision_force(); int id = collision_object_id(); say (avatar_name(k) + " a collisioné avec " + itos(id) + " force " + ftos(force)); }
key collision_avatar();
This function can then be used to determine the colliding avatar.
For event COLLISION, COLLISION_VEHICLE_AVATAR, COLLISION_VEHICLE_VEHICLE, COLLISION_VEHICLE_OBJECT.
float collision_force ();
This function can then be used to determine the collision force.
For event COLLISION_VEHICLE_AVATAR, COLLISION_VEHICLE_VEHICLE, COLLISION_VEHICLE_OBJECT.
int collision_object_id ();
This function can be used to determine the ID of the other object (vehicle or object).
For event COLLISION_VEHICLE_VEHICLE, COLLISION_VEHICLE_OBJECT.
Animated meshes allow the execution of animations on the rigged meshes of an object, without any avatar.
A rigged mesh can be based on the standard skeleton of the male or female avatar, or have a custom skeleton. In Edit Mesh, mode JOINTS, check the appropriate option.
An object worn on the avatar must always have its own custom skeleton if it wants to execute its own animations by script, independently of the avatar's animations.
void object_start_animation (string animation); void object_stop_animation (string animation);Starts or stops an animation on an object.
bool object_is_animation_active (string animation);
Tests if an animation is currently running on the given object.
void display_menu (key avatar, string menu [,string menu2[,string menu3[,string menu4, ..]]]);display a user menu.
event touch () { key k = touched_avatar(); display_menu (k, "On:1,Off:0,Color:[red:0xFF,green:0xFF00,blue:0xFF0000]"); } event menu_selected (key avatar, int menu_id) { say ("avatar " + avatar_name(avatar) + " has selected menu " + itos(menu_id)); }
void give_inventory (string item_name);gives the item of given name to the user's inventory.
string item_name (string previous_name [, int step]);lists all items present in the script folder of an object.
string item_type (string item_name);used to get the type of an item
event items_changed() { // user did add/modify/remove an item from scripts folder }
Example:
// give all items except those of type script : event touch() { string(32) name; clear name; for (;;) { name = item_name (previous_name => name); if (name == "") break; if (item_type (name) != "SCR") { give_inventory (item_name => name); say ("giving " + name); } } }
The following script commands allow to automatically dress and undress an avatar. They drag objects, textures, shapes and animations into the avatar's inventory and make it wear them, or take them off.
If an avatar has just arrived on the planet and his clothes are not yet loaded, then a script running clothing commands will be paused until all his clothes are loaded. A clothing script can therefore sometimes pause for almost a minute in case of a slow connection before continuing its execution. This mechanism prevents the wrong clothes from being put on the avatar.
void wear_object (key avatar, string item_name, bool permanent = false);
Automatically make an avatar wear an object.
The object to be worn must be in the "Scripts" folder of the object that runs this script.
The object is added to the avatar's inventory, in the "Object" folder if permanent is true, otherwise in the "Temporary" folder.
An object in "Temporary" is limited: when it is removed, it is moved to the "Trash" folder and the avatar cannot change or reuse the object after that.
void unwear_object ();Remove the worn object that runs this script.
void unwear_object (key avatar, string item_name);Removes the worn object from an avatar.
string next_worn_object (key avatar, ref int snr);Lists all worn objects
event detached (key avatar, string name) { }
void wear_texture (key avatar, string item_name, bool permanent = false);
Automatically make an avatar wear a texture.
The texture to be worn must be in the "Scripts" folder of the object that runs this script.
The texture is added to the avatar's inventory, in the "Textures" folder if permanent is true, otherwise in the "Temporary" folder.
An texture in "Temporary" is limited: when it is removed, it is moved to the "Trash" folder and the avatar cannot reuse the texture after that.
void unwear_texture (key avatar, string item_name, int body_part = -1, int layer = -1);
Removes the worn texture from an avatar.
The characters '? (replaces 1 char) and '*' (replaces multiple chars) are allowed in item_name to remove multiple textures.
body_part : 0=head, 1=chest, 2=legs, 3=eyes, 4=finger nails, 5=toe nails, -1=all
layer : 0=skin, 1=tatoo, 2=underwear, 3=clothing, 4=overwear, -1=all
void wear_shape (key avatar, string item_name, bool permanent = false);
Automatically make an avatar wear a shape.
The shape to be worn must be in the "Scripts" folder of the object that runs this script.
The shape is added to the avatar's inventory, in the "Shapes" folder if permanent is true, otherwise in the "Temporary" folder.
An shape in "Temporary" is limited: when it is removed, it is moved to the "Trash" folder and the avatar cannot change or reuse the shape after that.
void unwear_shape (key avatar, string item_name);
Removes the worn shape from an avatar.
The characters '? (replaces 1 char) and '*' (replaces multiple chars) are allowed in item_name to remove multiple shapes.
void wear_override_animation (key avatar, int typ, string item_name, bool permanent = false);
Automatically make an avatar wear an animation.
The animation to be worn must be in the "Scripts" folder of the object that runs this script.
The animation is added to the avatar's inventory, in the "Animations" folder if permanent is true, otherwise in the "Temporary" folder.
An animation in "Temporary" is limited: when it is removed, it is moved to the "Trash" folder and the avatar cannot change or reuse the animation after that.
The animation is also added to My Animations.
typ: 0=standing, 1=walking, 2=running, 3=flying, 4=jumping, 100-103 = permanent, 1 to 4 200-207 = individual, 1 to 8 300-307 = couple A, 1 to 8 400-407 = couple B, 1 to 8An empty item_name deletes the animation.
Blockings can be applied to avatars that are within a box-shape space around a rezzed object.
struct space { vector min, max; } // Apply blockings to an avatar. // The avatar must be in the same domain as the object. // If the avatar parameter is empty, the commmand applies to all avatars // that are inside the space. // options: // CAPTIVE : 0x0001 means avatar can't leave box space. // FLY : 0x0002 means avatar can't fly. // INVENTORY : 0x0008 means avatar can't open inventory. // NAMES : 0x0010 hides avatar names in People and Conversation, and blocks other people's profiles. // TELEPORT : 0x0020 means avatar can't teleport. // SENDCHAT : 0x0040 block sending on chat (except on worn objects with event listen) // READCHAT : 0x0080 block receiving on chat (except from commands say/say_to from worn objects) // CAMERA : 0x0200 means avatar can't move camera outside box space. // TOUCH : 0x0400 means avatar can't touch objects outside box space. // RADAR : 0x0800 means avatar can't see anyone in People dialog. // JUMP : 0x1000 means avatar can't jump. // several options can be added. // 0 means no blockings. // any script recompilation or script error in the object removes also all blockings. // space can be as large as 512m x 512m (-256.0 to +256.0) void block_avatar_options (key avatar, int options, space space);
// retrieve avatar block options int avatar_block_options (key avatar);
// retrieve next avatar having blockings. // clear avatar on first call, empty returned key means no further avatar is blocked. key next_avatar_blocked (key avatar);
void block_worn_object (blocking_parameters parameters);Block avatar features.
struct blocking_parameters { int options; float walking_speed; // in meters. if less than 3.2 m/s then running is blocked too. float camera_distance; // in meters. float touch_distance; // in meters. float radar_distance; // in meters. 0.0 to 256.0 float camera_angle; // angle in degrees. 0.0 to 180.0 uint fog_setting; // 0xKS_BBGGRR, example: 0xfe_000000 } // with : // K = frontier between non-fog and fog, from 0=progressive to F=hard, // S = distance of fog, from 0=far away to F=nearby, // BBGGRR = rgb fog color. // options: // 0x0001 : block menus 'unwear' and 'properties' for this object // 0x0002 : block flying // 0x0004 : block menus 'wear'/'unwear' of skins and clothes textures // 0x0008 : block inventory // 0x0010 : hides avatar names in People and Conversation, and blocks other people's profiles // 0x0020 : block teleport // 0x0040 : block sending on chat (except on worn objects with event listen) // 0x0080 : block receiving on chat (except from commands say/say_to from worn objects) // 0x0100 : limit walking speed, see .walking_speed // 0x0200 : limit camera distance, see .camera_distance // 0x0400 : limit touch distance by left click, see .touch_distance // 0x0800 : limit distance avatar are seen in People, see .radar_distance // 0x1000 : block jump // 0x2000 : fix camera on avatar's mFace bone // 0x4000 : limit horizontal and vertical camera view angle, for example .camera_angle = 45; // 0x8000 : set fog, see .fog_setting // 0x10000 : make avatar invisible for myself (my shadow remains visible).
An avatar that is blocked can click button CheatOut in profile to erase all blockings, but it is then added in the Cheats list in domain info.
Text files can be added in the scripts and read line by line.
// counts number of lines of a text file int count_lines (string item);
// returns line n of a text file string read_line (string item, int line);
Example:
// read all lines of a text file event start() { int count = count_lines ("mytext"); int i; for (i=1; i<=count; i++) { string(128) s; s = read_line ("mytext", i); say (s); } }
void store (string index, string value); // insert or update value associated with index
store() is used to save a string value on permanent server storage linked
to the object's id.
You can store a maximum of 10,000 strings, after that you get a script error.
The strings are not deleted when the script is restarted, the only way to delete all storage is to delete the object and rezz a new one.
You can delete one individual string value by storing an empty string.
Index must not be longer than 50 characters and contain only non-nul characters.
string fetch (string index); // retrievefetch() is used to retrieve a value previously saved with store(). If there was none, an empty string is returned.
string navigate (string index, int direction);returns index immediately smaller or larger than the provided index. direction can be -1 (smaller) or +1 (larger).
Example:
event start() { store (index => "hi-score", value => " 10 "); say (fetch(index => "hi-score")); // will say 10 }
Data can be permamently stored in the user's inventory, even if the user relogs or if the object is unworn and worn again.
void save_data_to_inventory (string index, string value);
store the string 'value' in the inventory on the client's pc
. for worn object only
. index must have maximum 50 characters and contain only non-nul characters.
. an empty string as value deletes the record.
. you can store max 10_000 records, further records are silently ignored.
void load_data_from_inventory (string index, int direction = 0);reloads a string that was previously stored in the client inventory
-1 = obtain index smaller than provided index, 0 = obtain provided index, +1 = obtain index larger than provided index.. returns an empty string index and value if no further index.
event inventory_data_arrived (string index, string value) { say ("index = '" + index + "'"); say ("value = '" + value + "'"); }
The command generate_particles() creates a particle emitter at the center of a mesh.
void generate_particles (particule_parameters p);
Example:
event start () { particule_parameters p; clear p; p.mesh_nr = 1; p.nb_particles = 10; p.pause = 1000; // sprayer p.direction_angle = {-180.0, +180.0}; p.height_angle = {0.0, 0.0}; p.radius = 0.5; p.life[0].durations = {15_000, 15_000}; // 15 seconds p.life[0].begin_speed = {1.0, 1.0}; // 1 m/s p.life[0].end_speed = {1.0, 1.0}; p.life[0].begin_color = {0xFFFFFFFF, 0xFFFFFFFF}; // white, 0% transparent p.life[0].end_color = {0xFFFFFFFF, 0xFFFFFFFF}; p.life[0].begin_size = {{0.2, 0.2}, {0.2, 0.2}}; // size 0.2 x 0.2 m p.life[0].end_size = {{0.2, 0.2}, {0.2, 0.2}}; p.life[0].orientation = 0; // always oriented vertically p.ambiant = true; p.sunlight = true; // p.texture = "brilliant"; // requires a texture called "brilliant" in folder scripts generate_particles (p); }
The structure particule_parameters contains the following fields :
struct particule_parameters { int mesh_nr; // mesh nr where the emitter is created // bursts int nb_particles; // number of particles emitted per burst int pause; // pause time between bursts, in milliseconds int nb_bursts; // number of bursts, 0 means infinite // particle birth in box vector[2] box; // particles are generated at random position within box // particle birth in sprayer float[2] direction_angle; // spray outward in horizontal angle range float[2] height_angle; // spray outward in vertical angle range float radius; // spray distance from center where particles are created // particle 3 lifetimes lifetime life[3]; // 3 successive lifes, see below. bool dont_follow_emitter; // true = if emitter mesh moves or rotates, particles don't follow. bool ambiant; // true = particles receive ambiant light bool sunlight; // true = particles receive sunlight float smooth; // gloss 0.0 .. 0.99 0.0 = rough, 0.99 = smooth float metal; // metal 0.0 .. 1.0 0.0 = other than metal, 1.0 = metal float translucid; // translucid 0.0 .. 1.0 0.0 = non-translucid, 1.0 = translucid bool front; // false = transparency priority -3, true = transparency priority +3. int emissive_color; // glow color string(32) texture; // particle texture name, must be added in scripts folder int mode_uv; // same as mesh u, v float u; float v; bool sort; // sort particles (nicer result for transparent textures but uses CPU !) // leash mode int leash_id; // id of object to link per leash (non-zero enables leash mode) int leash_mesh_nr; // mesh nr of distant object where to attach the leash (1 .. 32) float leash_length; // leash length in meters (maximum 256) float leash_stretch; // stretch factor (0..1) so that the particles overlap a bit at maximum length (0.0 = none, 0.2=chain rings) bool leash_physics; // true = pulls avatar back if further away than leash_length }
Particles can have a maximum of 3 lifes during which they have a different behaviour.
The structure lifetime contains the fields hereafter.
When there are two fields, you can specify a lower and a higher limit, and a random value between both limits is selected for each particle.
struct lifetime { int[2] durations; // particle life duration range, in msecs (max 1 day) float[2] begin_speed; // sprayer begin speed range float[2] end_speed; // sprayer end speed range vector[2] begin_velocity; // additional begin velocity in m/s vector[2] end_velocity; // additional end velocity in m/s vector[2] begin_acceleration; // additional begin acceleration in m/s2 vector[2] end_acceleration; // additional end acceleration in m/s2 vector[2] begin_size; // begin particle size (width, height) in meters vector[2] end_size; // end particle size (width, height) in meters int[2] begin_color; // begin color and transparency int[2] end_color; // end color and transparency int orientation; // 0=vertical on screen, 1=towards velocity, 2=horizontal in world, 3=chained. }
To stop particles, set p.mesh_nr or p.nb_particles to zero.
Example:
event start () { particule_parameters p; clear p; generate_particles (p); }
Here's a snow script with 2 lives: first the snowflake falls, then it stays on the ground for a while.
event start () { particule_parameters p; clear p; p.mesh_nr = 1; p.nb_particles = 1; p.pause = 200; p.emissive_color = 0xFFFFFF; // always lighten p.smooth = 0.93; // gloss 0.0 .. 0.99 0.0 = rough, 0.99 = smooth p.box = {{-32.767, -32.767, 0.0}, {32.767, 32.767, 0.0}}; // box that covers all area p.direction_angle = {-180.0, +180.0}; p.height_angle = {0.0, 0.0}; p.life[0].durations = {60000, 60000}; p.life[0].begin_speed = {0.0, 0.0}; p.life[0].end_speed = {0.0, 0.1}; // small direction speed p.life[0].end_velocity = {{0.0, 0.0, -0.2}, {0.0, 0.0, -0.2}}; // fall speed p.life[0].begin_size = {{0.10, 0.10}, {0.10, 0.10}}; p.life[0].end_size = {{0.10, 0.10}, {0.10, 0.10}}; p.life[0].begin_color = {0xFFFFFFFF, 0xFFFFFFFF}; p.life[0].end_color = {0xFFFFFFFF, 0xFFFFFFFF}; p.life[0].orientation = 0; // orientation vertical p.life[1].durations = {60000, 60000}; p.life[1].begin_size = {{0.10, 0.10}, {0.10, 0.10}}; p.life[1].end_size = {{0.10, 0.10}, {0.10, 0.10}}; p.life[1].begin_color = {0xFFFFFFFF, 0xFFFFFFFF}; p.life[1].end_color = {0xFFFFFFFF, 0xFFFFFFFF}; p.life[1].orientation = 2; // orientation horizontal // p.texture = "flocon"; // add a texture "flocon" in the script folder generate_particles (p); }
void play_sound (string item_name, float volume = 1.0, // 0.0 to 1.0 float radius = 20.0); // 0 to 1024 mPlay a sound.
Examples:
play_sound ("ding"); play_sound ("ding", volume => 1.0); play_sound ("ding", volume => 1.0, radius => 20.0);
void start_ambiant_sound (string item_name, float volume = 1.0, // 0.0 to 1.0 float radius = 20.0); // 0 to 1024 mPlays a sound in a loop.
Examples:
start_ambiant_sound ("sea"); start_ambiant_sound ("sea", volume => 1.0); start_ambiant_sound ("sea", volume => 1.0, radius => 20.0);
void stop_ambiant_sound ();
void media_play (key avatar, string url);
Plays a multimedia file or stream (mp3, mp4, wav, ..)
Empty or illegal url will stop the media.
Providing an url that is currently playing has no effect.
For a video media you need to build a rectangular mesh screen with ratio width=4 height=3, disable Ambiant and Sunlight, set Color and Glow to 255,255,255, and then go in menu "Mesh / Various" and enable option 'Video'.
Example:
event touch() { key k = touched_avatar(); media_play (k, "http://dino.com/tina.mp4"); }
void media_pause (key avatar, bool on);Pause or restart media
Examples:
media_pause (k, on => true); // pauses media_pause (k, on => false); // restarts
void media_seek (key avatar, int mode, float seconds);Changes media play position
. mode 0 : move to absolute position in seconds . mode 1 : move relative position in seconds (seconds can be negative) . mode 2 : relative from end (seconds must be negative)
Example:
media_seek (k, mode => 1, seconds => -5.0); // move 5 secs backwards
void media_volume (key avatar, float volume); // 0.0 to 1.0Changes media volume.
Example:
media_volume (k, volume => 0.5); // half volume
You can exchange UTF-16 strings of maximum 1024 characters with an external tcp/ip server using the following commands :
void tcp_open (string ip, int port); void tcp_close (); void tcp_send (string message);
and these script events :
event tcp_received (string message) event tcp_disconnected ()
Strings are sent with a 2-byte prefixed length field.
You cannot send more than one string per second.
In case of event server_restart(), the connection is lost and must be reopened.
You can obtain the planet server hostname and port using :
string server_name (); // max 256 characters int server_udp_port(); // used for planet, usually 13000 int server_tcp_port(); // used for web, usually 80
With your mouse, you can drag & drop images from your hard disk
to display them on an in-world object.
Example:
event image_dropped () { set_mesh_texture (1, ""); // apply image to mesh 1 }
The mesh display should have a 4/3 format (width = 4, height = 3).
Images will be automatically resized and centered with a transparent border.
The command set_mesh_texture(mesh_nr, ""); will have an effect only :
. for world objects (not attachments), . for commands, (not in a job), . in event image_dropped only.
In all other cases, it restores the default mesh texture.
Inside an event image_dropped, the following calls are allowed :
key touched_avatar (); // who did the drag & drop int touched_mesh_nr (); // on what mesh nr was it dropped world_position touched_world_position (); // on what world position vector touched_mesh_position (); // on what mesh position
void show_money_dialog (key avatar);
Displays a money dialog window on the avatar's viewer.
string money_balance (key avatar);
Returns user's money balance, example "+124.50"
int give_activity_money (key beneficiary);Transfers daily planet activity bonus money on user's account.
void ask_money_payment (key customer, int amount, string comment);
Asks the customer to pay the amount to the script owner.
The amount must be between 1 and 999_999
A 5% tax is deduced from the amount when the money is coming from someone else.
The function generates the event money_received when the customer accepts.
event money_received (key customer, int amount, string comment);
This event is generated when the customer just paid the amount to script owner.
Example:
// payment script const int PRICE = 1; // prix, price, preis void act (int action) { string(32) name; clear name; for (;;) { name = item_name (previous_name => name); if (name == "") break; if (item_type (name) != "SCR") { if (action == 1) { ask_money_payment (touched_avatar(), PRICE, name); break; } else { give_inventory (item_name => name); say ("gives " + name); } } } } event touch() { act (1); } event money_received (key customer, int amount, string comment) { act (2); }
int give_money (key beneficiary, int amount, string comment);
Transfers money from script owner to beneficiary.
In the object's Access tab you must set option "distribute money".
An empty beneficiary gives money to planet central bank.
The amount must be between 1 and 999_999.
The function returns an error code :
0 transfer was successful -3 illegal amount, must be between 1 and 999_999 -4 insufficient funds -5 not allowed in worn object -6 object not allowed to distribute money, see Access tab
int area_bonus (int amount);
This function increases an area maximum cost.
To use it, rezz the object on the area you want to increase.
You get 1 extra land cost per 10ρ of money, til a hard limit of 9000 area cost.
The function works only in an event touch or menu, and only if the script owner is the person who touches or clicks the menu.
The touching avatar's account gets debited.
The function returns an error code :
0 ok -3 illegal amount, must be between 20 and 999_999. -4 insufficient funds. -5 not allowed in worn object. -6 illegal area (not owned). -7 cost (area is already at maximum cost 9000). -8 only in event touch or menu_selected. -9 touching avatar must be object owner.
pid get_planet_id ();
Obtain the unique planet id (pid) of this planet.
A pid is defined as:
typedef int[2] pid;
Example:
event start() { pid p; p = get_planet_id (); say ("planet = {" + itos(p[0]) + ", " + itos(p[1]) + "}"); }
bool same_pid (pid a, pid b);
Tests if two planet id's are identical.
void send_message_to_planet (pid planet, int object_id, string message);
Send a message to an object on a specified planet, where it will trigger an event planet_message_received.
void broadcast_message_to_planet (pid planet, string script_name, string message);
Send a message to all scripts of the given name on a specified planet, where it will trigger an event planet_message_received.
This event is triggered when a message was received, from an object on another (or same) planet.
Inside the event, the function sender_object_owner() can be used to obtain the owner of the scripted object that sent the message.
Example:
event planet_message_received (pid planet, int object_id, string message) { say ("on planet {" + itos(planet[0]) + ", " + itos(planet[1]) + "}" + " user " + avatar_name (sender_object_owner()) + " object " + itos(object_id) + " sent us message '" + message + "'"); }
key sender_object_owner();
obtain the owner of the scripted object that sent the message.
Can be used only in event planet_message_received.
void teleport_to_planet2 (key k, pid planet); void teleport_to_planet2 (key k, pid planet, int domain);
Teleports avatar k to a planet and optionally to a domain.
The domain must be visible in public search.
The script object must have at least rank security officer on the origin domain.
To configure the combat mode, choose the menu Tools / Settings: activate the combat mode via the C or F6 key, select if you want to run all the time, and choose the mouse speed.
To enter combat mode, press F6 or C.
void set_arm_range (float distance);
set the range the selected arm will cover, in meters.
void set_arm_power (int power);
set the power (the amount of damage) the selected arm will inflict.
event shot (key victim, int power)
this event is called when we shot a victim.
event damage (key shooter, int power)
this event is called when we have been shot.
Example:
event start() { set_arm_power (3); set_arm_range (1024.0); } event shot (key victim, int power) { say ("shot " + avatar_name (victim) + " " + itos(power)); } event damage (key shooter, int power) { say ("ouch! damage from " + avatar_name (shooter) + " " + itos(power)); }
struct ray_casting { // input int mask; // 1 = detect objects, 2 = detect avatars, 3 = both. world_position origin; // origin position of ray vector direction; // ray direction, unit vector, ex: {0.0, 0.0, -1.0} pointing down. float max_distance; // ray travelling distance, in meters (0.001 to 100.0) float radius; // ray radius, in meters, (0.0 to 10.0) // output int typ; // 0 = no collision, 1 = collided with object, 2 = collided with avatar. world_position position; // collision position float distance; // in meters (less than max_distance in case of collision) vector normal; // collision normal vector. ex: {0.0, 0.0, 1.0} for collision with ground floor. // output for typ 1 (object) : int object_id; // id of collisioned object int mesh_nr; // nr of collisioned mesh (1 .. 32) vector mesh_position; // local position of mesh collided by ray // output for typ 2 (avatar) : key avatar; // key of collided avatar (if typ == 2) }
bool cast_ray (ref ray_casting r);
Launches an invisible beam and detects the first non-phantom object or avatar it touches.
You must fill in the input fields before calling the function, and read the results in the output fields.
The function returns true if an object or avatar is touched, false otherwise.
Exemple:
event touch() { ray_casting r; say ("============="); clear r; r.mask = 3; r.origin = object_world_position (object_id()); r.direction = {0.0, 0.0, -1.0}; // downwards r.max_distance = 100.0; // 100 meter r.radius = 0.001; // 1 mm say ("origin = " + itos(r.origin.x>>8) + " " + itos(r.origin.y>>8) + " " + itos(r.origin.z>>8) + " mm"); if (cast_ray (ref r)) { say ("ray touched"); say ("typ = " + itos(r.typ)); say ("id = " + itos(r.object_id)); say ("pos = " + itos(r.position.x>>8) + " " + itos(r.position.y>>8) + " " + itos(r.position.z>>8) + " mm"); say ("mesh_nr = " + itos(r.mesh_nr)); say ("distance = " + ftos(r.distance) + " m"); say ("z = " + itos(r.position.z / 256) + " mm"); say ("mesh pt = " + ftos(r.mesh_position.x) + ", " + ftos(r.mesh_position.y) + ", " + ftos(r.mesh_position.z)); say ("normal = " + ftos(r.normal.x) + ", " + ftos(r.normal.y) + ", " + ftos(r.normal.z)); say ("avatar = " + avatar_name (r.avatar)); } else say ("no collision"); }
void earthquake (int intensity, // 0 to 100 float duration); // 0.0 to 30.0 sec
Initiates an earthquake of given intensity and duration. You need to be land owner to use this.
string itos (int value, int width=0, string filler=" "); // example: itos(23, 5, "0") == "00023" string ftos (float value, int width=0, int decimals = 3); // example: ftos(23.2, 5) == " 23.2" string btos (bool value, int width=0); // example: btos(b) == "true" bool stob (string str); // example: stob(" true ") == true int stoi (string str); // example: stoi("-23") == -23 float stof (sring str); // example: stof(" 13.7 ") == 13.699 float itof (int value); int ftoi (float value); // truncates
int len (string value); // example: len("abc") == 3 string chr (int c1, int c2, int c3, ..., int c16); // example: chr(65,66,67) == "ABC" int asc (string value, int index=1); // example: asc("AB") == 65 asc("ABC",2) == 66 string left (string value, int count); // example: left("ABCD",2) == "AB" string right (string value, int count); // example: right("ABCD",2) == "CD" string mid (string value, int index, int count=); // example: mid("ABCDEF",2,3) == "BCD" mid("ABCDEF",5) == "EF" int pos (string phrase, string word); // example: pos("ABCDEF","CD") == 3 pos("ABCDEF","X") == 0 string dup (string value, int count); // example: dup("-*",3) == "-*-*-*" string upper (string value); // remove accents and convert to upper case string lower (string value); // remove accents and convert to lower case string trim (string value); // remove leading and trailing spaces string ltrim (string value); // remove leading spaces string rtrim (string value); // remove trailing spaces string resolve_icons (string value); // converts sequences like :) in icon codes
struct date_time { int year; /* 1901 to 9999 */ int month; /* 1 to 12 */ int day; /* 1 to 31 */ int hour; /* 0 to 23 */ int min; /* 0 to 59 */ int sec; /* 0 to 59 */ int msec; /* 0 to 999 */ } date_time now (); // gmt time int weekday (date_time date); // (1=monday, 7=sunday) date_time add_seconds (date_time date, int seconds); int area_time_offset (); // seconds to add to gmt time to obtain local area time int nb_days_since_1901 (date_time date); // nb days between 1/1/1901 and date
int abs (int value); int min (int a, int b, int c, .., int h); int max (int a, int b, int c, .., int h); int rnd (int a, int b); float frnd (); // value between 0 included and 1 excluded float fabs (float value); float sin (float angle); // angle in degrees float cos (float angle); // angle in degrees float atan2 (float y, float x); // result angle in degrees float sqrt (float angle); float trunc (float angle); float round (float angle); float fmin (float a, float b, float c, .., float h); float fmax (float a, float b, float c, .., float h);
Some script commands that act on avatars require authorisations, otherwise they have no effect.
In particular the following commands require an authorisation :
sit, start/stop_animation, wear/unwear_xxx, block_avatar_options, display_menu, media_xxx, show_money_dialog, set_avatar_world_position, teleport_to_planet.
Authorization is granted in 3 cases :
a) if avatar A triggers an event (for example A clicks, event touch), then the script can act on A.
b) if the object belongs to avatar A, or is worn by A, then the script can act on A.
c) if the object belongs to avatar A, or is worn by A, and A is at least security officer on the domain, then the script can act on all avatars.
If the event was not triggered by A (for example an event start or timer), nor A does own the object, nor the object's owner is at least security officer, then the command has no effect on A.
// door script bool g_is_open; event touch () { float angle; g_is_open = !g_is_open; if (g_is_open) angle = 120.0; else angle = 0.0; set_mesh_rotation (mesh_nr => 1, rotation => {0.0, 0.0, angle}); }
// door script with closing after 10 seconds bool g_is_open; event touch () { float angle; g_is_open = !g_is_open; if (g_is_open) angle = 120.0; else angle = 0.0; set_mesh_rotation (mesh_nr => 1, rotation => {0.0, 0.0, angle}); start_timer (nr => 0, seconds => 10.0); } event timer (int nr) { set_mesh_rotation (mesh_nr => 1, rotation => {0.0, 0.0, 0.0}); g_is_open = false; }
// lamp script bool g_is_enabled; event touch () { float range; g_is_enabled = !g_is_enabled; if (g_is_enabled) range = 2.0; else range = 0.0; set_mesh_light (mesh_nr => 1, color => 0xFFFFFF, attenuation => 0.6, range => range); }
Local variables are not included.