In jedem 3D-Objekt können Sie Skripte hinzufügen, die ausgeführt werden und das Objekt lebendig machen.
So erstellen Sie ein Skript :
- ein Objekt bearbeiten (Objekt > Bearbeiten), gehen Sie auf die Tab "Skripte" und klicken Sie auf "Zufügen".
- Wählen Sie die Zeile "1 SCR Script" aus und klicken Sie auf "Editieren".
- Schreiben Sie Ihr Skript in dem Editor und klicken Sie auf die Taste "Anwenden".
In der Skriptliste steht * für einen Kompilierungsfehler und ! für einen Laufzeitfehler.
Klicken Sie im Editor auf die Taste "Fehler Zeigen", um alle Details zu Laufzeitfehlern anzuzeigen.
Die Planet-Skriptsprache ist eine einfache Ableitung der C-Familie.
Datentypen sind: bool, int, float, array, struct und string(N) mit N in 0 .. 1024.
Ein Skript besteht aus: const, globalen Variablen, typedef, Funktionen und Ereignishandlern.
Funktionen und Ereignishandler können const, typedef und lokale Variablen enthalten.
Funktionsparameter können den Modus 'in' (standardmäßig), 'ref', oder 'out' haben.
In dem Fall, dass ein Funktionsparameter oder ein Funktionsrückgabewert vom typ string ist, muss dieser ohne maximale Längenangabe erscheinen.
Zu den Steueranweisungen gehören: if, switch, for, while, break, continue, assert, abort, clear (zum löschen von Variablen).
Konstanten/Werte vom typ array/struct können als Aggregate erscheinen, z.B.: {1, 2, i}
Operatoren umfassen unär: + - ! ~ -- ++ und binär: * / % + - << >> == != < > <= >= && || & | ^
Ein typisches Skript verarbeitet kurze Ereignisse aus dem Planetensystem, wie das Öffnen einer Tür, wenn der Benutzer darauf klickt.
Wenn Ihr Skript eine sehr große Anzahl von Anweisungen pro Tag ausführt, ist das nicht normal. Planet wird es dann benachteiligen, indem er es verlangsamt.
Ein Skript, das sehr viele Anweisungen pro Tag ausführt, ist wahrscheinlich schlecht geschrieben :
- entweder kreist es in Endlosschleifen,
- oder es führt den ganzen Tag über Timer-Ereignisse mit zu kurzen Laufzeiten aus,
- oder es empfängt eine große Menge an Nachrichten von anderen Skripten.
Wir empfehlen Ihnen, den Befehlsverbrauch Ihrer Skripte über das Menü Werkeuge > Skripte zu überprüfen. Überprüfen Sie die Spalte 'CPU-Gebrauch' : Wenn sie mehr als 1.000 Einheiten anzeigt, könnte ein Problem vorliegen. Bei mehr als 10.000 gibt es sicherlich Verbesserungen vorzunehmen oder Fehler zu beheben. Sie können Anweisungen say() z. B. in den Event Timer setzen, um zu überprüfen, wann er ausgelöst wird.
Während das Fenster Werkeuge > Skripte geöffnet ist, steigen kleine rote Blasen über einem Objekt auf, wenn ein Skript seine Position oder sein Aussehen ändert.
Zu viele rote Blasen deuten auf ein schlecht geschriebenes Skript hin, das seine Befehle nacheinander absendet,
anstatt wie in Kapitel 4.22 erklärt einen Bewegungsbatch zu verwenden.
Bewegungsbatches sind sehr empfehlenswert, da sie während der Laufzeit weder Server-CPU noch Netzwerk-Traffic verbrauchen.
Außerdem ermöglichen sie gleichmäßige und ruckelfreie Bewegungen.
Wenn das Skript kompiliert wird oder das Objekt aus dem Inventar entnommen oder getragen wird, wird das Skript vollständig auf Null zurückgesetzt. Das START-Ereignis wird dann zuerst ausgeführt.
event start () { say ("Hallo, ich starte!"); }
Wenn der Benutzer mit der linken Maustaste auf das Objekt klickt, wird das TOUCH-Ereignis ausgeführt.
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)); }
Bei der Behandlung eines Touch-Ereignisses können folgende Funktionen aufgerufen werden:
// gibt einen eindeutigen permanenten Schlüssel zurück, der den Avatar bezeichnet, der auf das Object geklickt hat. key touched_avatar (); // liefert die Nummer des berührten Mesh (1 bis 32). int touched_mesh_nr (); // liefert die berührte Position in absoluten Weltkoordinaten (siehe unten). world_position touched_world_position (); // liefert die berührte Position in relativen Mesh-koordinaten (siehe unten). vector touched_mesh_position ();
Folgende Datentypen sind vordefiniert :
typedef int[4] key; // key ist ein einmaliger Schlüssel, der einen Avatar im Planet-System identifiziert struct world_position // eine Position auf dem Planeten { int x, y, z; // Koordinaten in 1/256 mm } struct vector // eine kleine Position oder Rotation { float x, y, z; // Koordinaten in meter, oder Rotation in grad }
Mit der Funktion same_key() kann überprüft werden, ob zwei Keys identisch sind :
bool same_key (key k1, key k2);
Mit der Funktion is_null_key() kann überprüft werden, ob ein Key Null ist :
bool is_null_key (key k);
Ein Ereignis COLLISION wird ausgeführt, wenn ein Avatar mit dem Objekt kollidiert.
// Avatar kollidierte mit einem geskripteten Objekt. 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)); }
Folgende Funktionen können innerhalb eines Ereignis COLLISION aufgerufen werden:
key collision_avatar(); // Avatar, der kollidierte int collision_mesh_nr(); // Mesh-Nummer, die kollidierte vector collision_normal(); // Avatar zum Objekt Normalvektor
Objekte mit Materie COLLISION haben keine Physik (wie Materie PHANTOM), aber sie erzeugen ein Ereignis COLLISION. Sie können als Sensor verwendet werden, um einen ankommenden Avatar zu erkennen.
Mehrere Objekte aus COLLISION-Material zu platzieren, die sich überlappen, ist keine gute Idee, weil nur einer von ihnen (zufällig) ein Kollisionsereignis auslösen wird. Sie werden dann den Eindruck haben, dass dieses Ereignis unzuverlässig ist, weil es nicht jedes Mal von dem gleichen Objekt ausgelöst wird.
Wenn ein Avatar eine Chatzeile sendet, erhält ein nahegelegenes Objekt die Chatzeile in dem Ereignis LISTEN.
// Objekt hört einen Avatar sprechen. event listen (key avatar, string message) { say (avatar_name(avatar) + " sagte " + message); }
Beachten Sie, dass Zuhörer Skripte in sich bewegenden Objekten vermieden werden sollten, sie arbeiten nicht zuverlässig.
Die Standardreichweite beträgt 50m, kann aber mit set_listen_range() geändert werden:
void set_listen_range (float range); // Bereich 0 bis 50m einstellen, Standard ist 50m.
Bei Nichtgebrauch ist es ratsam, range auf 0.0 einzustellen, um den Server CPU gebrauch zu reduzieren.
Um auch Server CPU zu reduzieren, können Sie einen Filter setzen, der nur einige Chatnachrichten erfasst:
void set_listen_filter (string filter);Der Standardfilter ist "*", um alle Nachrichten zu erfassen.
Beispiel:
filter "!*" erfasst nur Chatzeilen, die mit "!" beginnen, wie "!start" und "!stop".
Jedes Skript kann maximal 16 Timer (Nr. 0 bis 15) mit unterschiedlichen Laufzeiten starten.
Wenn ein Timer abläuft, wird das Ereignis TIMER mit der abgelaufenen Timernummer ausgeführt.
event start () { start_timer (nr => 0, seconds => 3.0); } // dieses Ereignis wird ausgeführt, wenn ein Timer abläuft. event timer (int nr) // nr is die Timernummer { say ("timer number " + itos(nr) + " expired"); }
Periodische Timer können erstellt werden, indem man den Timer jedes Mal neu startet, wenn er abgelaufen ist, jedoch erzeugt dies eine Latenz, so dass es so selten wie möglich verwendet werden sollte.
Beispiel:
event start () { start_timer (nr => 0, seconds => 0.0); } // dieses Ereignis wird ausgeführt, wenn ein Timer abläuft. event timer (int nr) // nr is die Timernummer { say ("Hallo !"); start_timer (nr => 0, seconds => 3.0); // nach 3 Sekunden wiederholen }
Skripte können sich gegenseitig Nachrichten schicken mit send_message oder broadcast_message.
void send_message (int object_id, string message); void broadcast_message (string script_name, string message);
Beispiel einer Sendung:
event touch() { send_message (object_id => 235, message => "Hallo an alle Skripts vom Objekt 235"); broadcast_message (script_name => "script1", message => "Hallo an alle Skripts auf dem Planeten die script1 heissen"); }
Das Ereignis message_received wird ausgeführt, wenn unser Skript eine Nachricht von einem anderen Skript erhält.
event message_received (int sender_object_id, string message) { say ("erhalten : " + message + " von " + itos(sender_object_id)); }
Die Funktion sender_object_owner() gibt den Besitzer des Objekts zurück, das uns die Nachricht gesendet hat.
key sender_object_owner();
Lesen Sie das Kapitel "Interplanetare Kommunikation", um Nachrichten zwischen Skripten zu versenden, die sich auf verschiedenen Servern befinden.
Das Ereignis server_restart wird aufgerufen, wenn der Planetenserver gerade gestartet wurde.
event server_restart() { say ("Hallo, der Planetenserver ist gerade neu gestartet."); }
Ein Skript kann dieses Ereignis verwenden, um alle uhrabhängigen Berechnungen erneut zu verarbeiten.
void say (string value);Anzeige von Text im Chat in einer Entfernung von 20m
// Beispiel: event start () { say ("hallo, ich starte !"); }
void say_to (key avatar, string value);Das Gleiche wie say, aber für einen einzelnen Avatar.
Mit den Codes chr(0,i) können Sie Icons anzeigen, ersetzen Sie i durch eine Zahl.
event touch () { string(32) s; int i; s = ""; for (i=0; i<16; i++) s = s + chr(0,i); say ("icons : " + s); }
Sie können ein Bild im Chat anzeigen, indem Sie es im Ordner Script ablegen.
event touch () { // erfordert eine "sun"-Textur im Skriptordner des Objekts say ("dies ist meine Sonne : " + image ("sun") + " :)"); }
Mit den Codes chr(1,i) können Sie die Schriftart ändern, mit chr(2,i) den Schriftstil und mit chr(4,i,j) die Farbe. Ersetzen Sie i und j durch Zahlen.
// Begrüßer 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);
Macht das Mesh aktiv oder inaktiv.
Inaktive Meshes sind unsichtbar und verursachen keine Avatar-Kollisionen.
Beispiel:
event start () { set_mesh_active (mesh_nr => 1, enable => false); // Mesh 1 inaktiv schalten set_mesh_active (mesh_nr => 2, enable => true); // Mesh 2 aktiv schalten }
void set_mesh_position (int mesh_nr, vector position);
Bewegt das Mesh innerhalb eines Objekts (Bereich -32.768 bis +32.767 meter).
Die Position wird als Vektor in x,y,z Koordinaten angegeben.
Beispiel:
event start () { set_mesh_position (mesh_nr => 1, position => {1.299, -0.893, 0.5}); }
void set_mesh_rotation (int mesh_nr, vector rotation);
Dreht ein Mesh innerhalb eines Objekts.
Die Drehung wird als x,y,z Winkel in Grad angegeben (-360.0 bis +360.0).
Die Drehachse ist der Mittelpunkt 0,0,0 des Mesh.
Beispiel:
event start () { set_mesh_rotation (mesh_nr => 1, rotation => {0.0, 0.0, 45.0}); }
void set_mesh_color (int mesh_nr, int color);
Ändert die Mesh-Farbe.
Farbe ist definiert als hexadecimaler RGB-Wert (0xBBGGRR).
Beispiel:
event start () { set_mesh_color (mesh_nr => 1, color => 0xFFC0D0); }
void set_mesh_transparency (int mesh_nr, float transparency);
Ändert die Mesh-Transparenz.
Der Transparenzwert muss zwischen 0.0 und 1.0 liegen.
Beispiel:
event start () { set_mesh_transparency (mesh_nr => 1, transparency => 0.3); }
void set_mesh_light (int mesh_nr, int color, float attenuation, // zwischen 0.0 und 1.0 float range, // zwischen 0.0 und 65.0 int cone); // 0=Punktlicht, oder Spotlicht grösse zwischen 1 und 255
Definiert ein Punkt oder Spotlicht an der Koordinate 0,0,0 des Meshes.
Um das Licht zu deaktivieren, rufen Sie diese Funktion mit 'range' gleich 0.0 auf.
Beispiel:
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 = Tageslicht erhellt das mesh bool sunlight); // true = Sonne erhellt das mesh
Ermöglicht es, das Tageslicht oder die Sonne, die ein Mesh erhellt, zu entfernen, zum Beispiel, wenn es sich in einem Keller befindet.
Beispiel:
event start () { set_mesh_lightning (mesh_nr => 1, ambiant => false, sunlight => false); }
void set_mesh_glow (int mesh_nr, int color);
Lässt ein Objekt im Dunkeln leuchten.
Beispiel:
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);
Bringen Sie alle Texturen dieses Meshes in Bewegung, indem Sie das UV dynamisch ändern.
Es gibt 6 Modi:
// mode 0 : uv ausschalten set_mesh_uv (mesh_nr => 1, mode => 0); // mode 1 : setzt statischen U,V Offset set_mesh_uv (mesh_nr => 1, mode => 1, u => 0.5, v => 0.3); // mode 2 : setzt gleitende U,V Offset // u, v ist die Gleitgeschwindingkeit set_mesh_uv (mesh_nr => 1, mode => 2, u => 0.1, v => 0.3); // mode 3 : Rahmen setzen // Die Textur muss aus N gleich großen, vertikal angeordneten Bildern bestehen. // Die aufeinanderfolgenden Bilder werden wie in einem Diaporama dargestellt. // u bezeichnet die Anzahl der Bilder und v die Änderungsgeschwindigkeit. // Der optionale Parameter ping_pong gibt an, ob wir die Bilder bei ihrem Ende wieder rückwärts anzeigen wollen. // Der optionale Parameter one_shot gibt an, ob wir alle Bilder nur einmal anzeigen oder für immer wiederholen wollen. 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 : rotierende Textur // u bezeichnet den maximalen Drehwinkel (360.0 für einen Vollkreis). // v bezeichnet die Drehzahl. // Der optionale Parameter ping_pong gibt an, ob wir uns bei Ende zurückdrehen wollen. // Die Drehung erfolgt bei u,v = 0,0, so dass, falls eine zentrierte Drehung gewünscht wird // sollten Sie die Textur u,v im Bereich von -0.5 bis +0.5 einstellen, wenn Sie das Mesh bearbeiten. 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 : Pulsierende Textur // u bezeichnet die Impulsstärke. // v bezeichnet die Geschwindigkeit. // Der optionale Parameter ping_pong gibt an, ob wir eine Hin- und Herbewegung wünschen. 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);
Schließlich kann die Option 'perlin' für horizontale Wasserstrukturen aktiviert werden.
void set_mesh_texture (int mesh_nr, string texture);
Ersetzt die Textur eines ganzen Meshes durch eine neue provisorische Textur.
Die neue Textur muss in das Verzeichnis Scripts des Objekts kopiert werden.
Einen leeren Texturnamen "" wird die originale Textur wieder herstellen.
Wenn Sie das Objekt auf dem Land rezzen bekomt es auch wieder seine original Textur.
Beispiel:
event start () { set_mesh_texture (mesh_nr => 1, texture => "checkboard"); }
int object_id();gibt die Objekt-ID zurück. Dies ist eine Nummer, die das Objekt auf diesem Planet-Server identifiziert, bis das Objekt gelöscht wird.
bool is_worn ();gibt true zurück wenn das aktuelle Objekt getragen wird, false wenn es auf dem Land ist.
string object_name ([int object_id]);gibt den Namen des Objekts zurück (max 32 Zeichen)
void set_object_name (string name);für ein getragenes Objekt, ändert vorübergehend den Namen des Objekts, so dass say()-Aufrufe einen anderen Namen verwenden.
key object_owner ([int object_id]);gibt den Besitzer des Objekts zurück.
string object_owner_date ([int object_id]);gibt ein Datum im Format "JJJJMMTT" zurück
int object_nb_meshes();gibt die Anzahl der Meshes des Objekts zurück.
int domain_id();gibt den Domain-ID zurück wo das Objekt sich befindet.
string domain_name();gibt den Domain-Namen zurück wo das Objekt sich befindet.
bool domain_adult();
prüft ob sich das Objekt auf einem erwachsenen Domain befindet.
int object_access();gibt die zugriffsrechte des Objekts zurück, eine Summe folgender Werte :
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
Sie können einzelne Zugriffe mit dem Operator & testen.
world_position object_world_position (int object_id);gibt die Weltposition des Objekts zurück.
vector object_rotation (int object_id);gibt die Rotation des Objekts zurück.
int set_object_world_position (int object_id, world_position position);bewegt das Objekt
-1 : schlechtes objekt_id -2 : keine Zugriffsrechte zum Verschieben dieses Objekts -3 : keine rezz-Zugriffsrechte auf dem neuen Area -4 : neuer Area ist voll.
Sie können ein Objekt über der See bewegen, aber es wird gelöscht
wenn es eine Stunde auf See bleibt, ohne dass ein Avatar es sieht.
Sie können ein anderes Objekt als das Skriptobjekt nicht verschieben,
wenn das Objekt getragen wird oder per Skript gerezzed wurde.
void set_object_rotation (int object_id, vector rotation);dreht das Objekt
int rezz_object_relative (string item_name [, vector position [, vector rotation]]); int rezz_object_absolute (string item_name , world_position position [, vector rotation]);
legt ein Objekt in der Welt nieder, entweder an einer relativen Position vom Skriptobjekt aus,
oder an einer absoluten Weltposition.
gibt einen positiven Wert (id des erstellten Objekts),
oder einen negativen Fehler zurück (-1 = keine rezz-Rechte, -2 = Area voll).
int clone_object (bool active);
legt eine Kopie des Objekts, das das Skript ausführt, genau an derselben Stelle ab wie das ursprüngliche Objekt.
mit active = true für eine exakte Kopie, oder false für eine Kopie, bei der alle Meshs ursprünglich deaktiviert wurden, damit es unsichtbar bleibt.
gibt einen positiven Wert zurück (id des erstellten Objekts), oder einen negativen Fehler (-1 = kein Recht auf rezzer, -2 = volle area, -3 = nicht erlaubt für ein getragenes Objekt).
int parent_object_id ();gibt eine positive ID des übergeordneten Objekts zurück, das dieses Objekt gerezzt, geclont oder getragen hat,
void delete_object();löscht das Objekt, das dieses Skript ausführt.
Wenn Sie ein Objekt auf dem Land rezzen und dieses Objekt gelöscht wird, dann erhält das Vaterobjekt, das es gerezzt hat, ein Ereignis child_died mit dem object_id des Objekts das gelöscht wurde :
event child_died (int child_id) { }
Beispiele:
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);listet alle Objekte im Area auf.
Beispiel:
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)); } }
Um ein Objekt oder ein Mesh zu bewegen, besteht der naive Weg darin, Befehle mehrmals pro Sekunde zu wiederholen. Dies führt jedoch zu ruckartigen Bewegungen, verbraucht viel CPU-Leistung und erzeugt eine Menge Internetverkehr. Kurz gesagt: Es erzeugt Lag.
Der seriöse Weg besteht darin, ein Bewegungsbatch zu verwenden. Dazu muss man im Voraus eine Sequenz von Bewegungen vorbereiten, die ausgeführt werden sollen. Die Sequenz wird komprimiert und ein einziges Mal an den PC gesendet, wo sie ausgeführt wird, ohne den Server zu stören. Um zum Beispiel eine Tür zu öffnen, werden Sie einen Batch erstellen, der nur die Bewegungszeit und die Enddrehung vorgibt, und der PC wird sich darum kümmern, alle Zwischenpositionen zu generieren. Der PC kann Ihre Sequenz sogar unzählige Male wiederholen, stellen Sie sich zum Beispiel einen Ventilator vor.
Bewegungsbatches sind sehr empfehlenswert, da sie während der Laufzeit weder Server-CPU noch Netzwerk-Traffic verbrauchen. Außerdem ermöglichen sie gleichmäßige und ruckelfreie Bewegungen.
Alle Befehle eines Batches müssen zwischen :
void begin_move (); void end_move ();
void move_job (bool repeating = false, bool sync = false, int sync_delay = 0); repeating : true um die Jobbefehle zu wiederholen. sync : true um mit anderen Jobs von gleicher Gesamtdauer zu synchronisieren (nur für repeating=true) sync_delay : ein Wert für die Synchronisationsverschiebung in Millisekunden (nur für sync=true).Sie können innerhalb eines Jobs einen oder mehrere der folgenden Befehle angeben:
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);
Wenn einer dieser Befehle zwischen begin_move() und end_move() angegeben wird, wird der Befehl, anstatt ihn sofort auszuführen, im Bewegungsbatch aufgezeichnet. Sobald wir bei end_move() angekommen sind, wird der Batch abgeschlossen, überprüft, komprimiert und zur Ausführung vom Server an den PC gesendet.
void job_duration (int duration); // Die Dauer muss >= 16 Millisekunden sein.
void stop_move ();Einige Regeln:
int end_move2 ();Anstelle von end_move(), das bei einem Areafehler stoppt, können Sie auch end_move2() verwenden die 0 zurückgibt wenn OK, oder einen negativen Fehlercode wenn die Area nicht überschritten werden kann.
int nb_queued_moves ();Sie können die Anzahl der in der Warteschlange stehenden Bewegungen abfragen, falls mehrere nicht-wiederhol Bewegungen anstehen. Beachten Sie, dass maximal 128 Wartende Bewegungen erlaubt sind, danach wird das Skript angehalten.
float rest_move_duration ();Gibt die Zeit in Sekunden zurück, die ein nicht-wiederhol Batch benötigt, um anzuhalten.
Hier sind einige Beispiele:
Ein drehender Ventilator ------------------------ // Ventilator 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(); } }
Die Drehwinkel sollten weniger als 180° voneinander entfernt sein, um einen deterministischen Weg zwischen zwei Winkeln in 3D zu gewährleisten.
Ein gleichmäßiger Türbewegungsskript ------------------------------------ // Tür 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 (); } Fliegender Teppich ------------------ // Fliegender Teppich 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 (); } } Verblassendes Farbobjekt ------------------------ // Verblassendes Farbobjekt 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 (); } hüpfender Würfel ---------------- // hüpfender Würfel, der die Farbe wechselt. event start() { int i; begin_move (); // erster Job: hüpfende Position auf und ab 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); } // zweiter Job: Änderung der Drehwinkel 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); // dritter Job: Verblassen und Farbänderung 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);Liefert true, wenn ein Avatar online ist, false, wenn nicht.
string avatar_name (key k);Liefert einen aktuellen vollständigen Avatar-Namen (maximal 71 Zeichen).
int avatar_rank (key k);Gibt einen Avatar-Rang zurück : -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);Gibt true zurück, wenn der Avatar in den Mitgliedern der Domäne, auf der sich das Objekt befindet, vorhanden ist, sonst false.
void set_avatar_rank (key k, int rank);Ändert den Rang eines Avatars, wenn Sie Rechte dafür haben.
int avatar_gender (key k);Gibt ein Avatar-Geschlecht zurück : 0=male, 1=female.
int avatar_adult (key k);Gibt den Erwachsenen Status des Avatars wieder : 0=minderjärig, 1=Erwachsen, -1=key ungütltig.
int avatar_language (key k);Gibt die Sprache des Avatars zurück (0 = französisch, 1 = englisch, 2 = deutsch, -1 = key ungütltig)
int avatar_experience (key k);Gibt die Avatar experience zurück, oder -1 falls key unbekannt ist.
int avatar_timezone (key k);Gibt die Avatar timezone zurück, in Stunden, von -12 bis +12.
string avatar_title (key k);Gibt den Avatar title zurück, maximum 24 Zeichen.
world_position avatar_world_position (key k);Liefert eine Avatar-Weltposition (z ist 0, wenn man auf dem Boden in Höhe 0 steht).
int avatar_z_rotation (key k);Gibt eine Avatar-Orientierung zurück, wie folgt:
0 = Nord, gegenüber positivem Y 90 = Ost, mit positiver Ausrichtung X -90 = West, nach negativ X ausgerichtet -180 oder +180 = Süd, Richtung negativ Y
Beispiel:
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);Teleportiert einen Avatar.
Beispiel:
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);
teleportiert einen Avatar auf einen anderen Planetenserver.
Die Url muss die Form "planet://37.59.48.75/domain4" haben.
Falls angegeben, muss der domain in der öffentlichen Suche sichtbar sein.
Das Skriptobjekt muss mindestens den Rang security officer auf der Ursprungsdomäne haben.
Siehe auch den Befehl teleport_to_planet2 in Kapitel 21. Kommunikation zwischen Planeten.
key next_avatar (ref int snr);listet nacheinander alle Avatare in einem Radius von 256 Metern auf.
Beispiel:
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) { }
Das Ereignis owner_login wird aufgerufen, wenn sich der Eigentümer des Objekts an- oder abmeldet.
. es wird typischerweise für einen Präsenzwürfel verwendet.
. es funktioniert nicht bei getragenen Objekten.
int avatars_online_count();
berechnet die Anzahl der Avatare, die gerade auf diesem Planeten online sind (0 bis 1024).
key avatar_key (string name);
gibt den Avatarschlüssel zurück, der dem angegebenen Avatarnamen entspricht. Der Name kann etwas ungenau sein, dann wählt die Funktion den nächstliegenden Namen. Ein Nullschlüssel wird zurückgegeben, wenn der Avatar nicht gefunden wurde, was mit is_null_key() getestet werden kann.
bool is_sitting (key avatar);Testet, ob ein Avatar auf diesem Objekt sitzt.
bool sit (int mesh_nr, vector position, vector rotation, key avatar);Setzt einen Avatar mit Position/Rotation auf die mesh_nr dieses Objekts.
void unsit (key avatar);Lässt einen Avatar aufstehen, wenn er auf diesem Objekt sitzt und stoppt alle Animationen, die während der Sitzung gestartet wurden.
void start_animation (string animation, key avatar); void stop_animation (string animation, key avatar);Startet oder stoppt eine Animation.
bool is_animation_active (string animation, key avatar);Prüft, ob diese Animation aktuell auf dem angegebenen Avatar läuft.
void override_animation (int typ, string animation);Ersetzen von Standardanimationen (Stehen, Gehen, Laufen, Fliegen, Springen)
// Beispiel 1 : Tanzball 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); } // Beispiel 2 : auf einem Stuhl sitzen 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(); // key des Avatars, der klickt key k2 = clicked_avatar(); // key des Avatars, der angeklickt wird. say ("click " + avatar_name(k1) + " klickte auf " + avatar_name(k2)); }
Das Ereignis click_avatar() wird erzeugt, wenn der Benutzer auf einen Avatar klickt der auf einem Objekt sitzt. Alle Skripte dieses Objekts empfangen dann dieses Ereignis. Dies kann verwendet werden, um die Animation des Avatars zu ändern.
Folgende Funktionen sind innerhalb eines Ereignis click_avatar erlaubt :
key clicking_avatar(); // bekomt key vom avatar der klickt key clicked_avatar(); // bekomt key vom avatar auf dem geklickt wird.
Es kann sein, dass der Avatar bereits nicht mehr auf dem Objekt sitzt, wenn dieses Ereignis verspätet ankommt. Sie können dies mit is_sitting() überprüfen.
bool get_sitter (out sitter);
Gibt in mehreren Aufrufen alle Avatare zurück, die auf dem Objekt sitzen.
Gibt false zurück, wenn keine Avatare mehr vorhanden sind.
Bei jedem Ereignis wird wieder beim ersten Avatar begonnen.
Alle Avatare, die auf einem Objekt sitzen, können wie folgt aufgelistet werden:
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)); }
Der Struktur Sitter ist wie folgt definiert:
struct sitter { key avatar; int mesh_nr; vector position; vector rotation; }
Dies kann für Beispiel für Paar-animationen verwendet werden:
event touch() { key k = touched_avatar(); if (is_sitting (k)) // schon sitzend { unsit (k); // aufstehen } else { sitter s; if (get_sitter(out s) && s.mesh_nr == 1) { // jemand sitzt bereits auf dem Mesh 1. if (sit (mesh_nr => 2, // auf Mesh 2 sitzen 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, // auf Mesh 1 sitzen 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) { }
Das Ereignis avatar_unsits signalisiert, dass ein Avatar von einem Objekt aufsteht.
Es wird aufgerufen, wenn a) ein anderes Objekt sit() auf dem Avatar aufruft,
oder b) der Avatar sich weg teleportiert,
oder c) der Avatar die Verbindung trennt.
Es wird nicht aufgerufen, wenn a) das Objekt unsit() auf den Avatar aufruft,
oder b) das sitzende Objekt gelöscht wird, oder c) der Planetenserver stopt.
Nachdem Sie einen Avatar gesetzt haben, können Sie dessen Kamerastabilität einstellen.
void set_camera_stability (int stability, key avatar);Die folgenden drei Stabilitätswerte sind möglich:
0 = STABIL (Kamera immer horizontal) (dies ist die Standardeinstellung nach dem Sitzen) 1 = DYNAMISCH (horizontale und vertikale Kameradrehungen sind erlaubt) 2 = UNRESTRICTED (Kamera folgt dem Avatar, alle Kameradrehungen sind erlaubt, aber Vorsicht, sonst wird man seekrank)
Zusätzliche Passagiere können ebenfalls auf dem Fahrzeug sitzen und ihre Kamerastabilität einstellen, aber nur ein Fahrer kann control_vehicle() aufrufen; alle vorherigen Fahrer werden zu Passagieren.
void control_vehicle (vehicle_parameters p, key avatar); struct vehicle_parameters { bool active; // true = verhält sich wie ein Fahrzeug, false = Fahrzeugmodus aus //--------------------------------- // Physik float mass; // 1000 kg float max_speed; // in km/h maximale Geschwindigkeit vector dimensions; // Fahrzeugabmessungen (Größe, Länge, Höhe) (0.6 bis 32.767 Meter) Die Fahrzeugphysik wird als eine gedehnte Blase mit diesen Abmessungen modelliert. int nb_wheels; // 1 (Einrad), 2 (Fahrrad), 3 (Dreirad), oder 4 (Auto) (1 bis 4) Unter dem Fahrzeug befinden sich Räder, die als komprimierbare Kugeln modelliert sind und es nach oben drücken. Die Anzahl der Räder hat einen Einfluss auf das Gleichgewicht des Fahrzeugs. Wenn die Anzahl der Räder 1 ist, handelt es sich um ein Fahrzeug, das immer horizontal bleibt (Einrad) wenn die Anzahl der Räder 2 ist, kann es sich um ein Fahrrad handeln (Räder hintereinander) wenn left_to_right_wheel_distance = 0 und axis_to_axis_distance > 0 ist, oder ein Segway (ein Rad auf der linken und eines auf der rechten Seite) wenn left_to_right_wheel_distance > 0 und axis_to_axis_distance = 0. Wenn die Anzahl der Räder 3 ist, gibt es ein Rad vorne in der Mitte und zwei Räder hinten. Wenn die Anzahl der Räder 4 beträgt, handelt es sich um ein klassisches Auto. Die Räder sind zentriert und gemäß left_to_right_wheel_distance und axis_to_axis_distance angeordnet. float tyre_radius; // 0.25 (0.001 bis 32.767 meter) Radius einer Radkugel, in Metern. float left_to_right_wheel_distance; // (0.0 bis 32.767 meter) Abstand zwischen dem Mittelpunkt der linken Radkugel und dem Mittelpunkt der rechten Radkugel, in Metern (0.0 à 32.767) Bei einem Fahrrad müssen Sie den Wert 0.0 angeben. float axis_to_axis_distance; // (0.0 bis 32.767 meter) (0.0 für einen Segway) Abstand zwischen dem Mittelpunkt der Vorderradkugel und dem Mittelpunkt der Hinterradkugel, in Metern (0.0 bis 32.767) bei einem Segway müssen Sie 0.0 angeben. dies beeinflusst den Radius des Kreises, in dem das Fahrzeug dreht (ein LKW dreht auf einem grösserem Kreis als ein Auto) bool set_z_range; // true = Fahrzeug nur im Höhenbereich min_z bis max_z erlaubt, false = keine Einschränkung. Wenn Sie die zulässige Höhenlagen des Fahrzeugs begrenzen wollen, setzen Sie set_z_range auf true. float min_z; // (-8000.0 bis 8000.0 meter) (0.0 für ein schiff) float max_z; // (-8000.0 bis 8000.0 meter) (0.0 für ein schiff) Sobald set_z_range true ist, können Sie hier einen Bereich festlegen, zum Beispiel: Setzen Sie min_z und max_z auf 0.0 für ein Schiff, damit es immer auf Meereshöhe ist. Setzen Sie min_z auf 0.0 und max_z auf 8000.0 für ein Hovercraft, so dass es nicht unter den Meeresspiegel sinken kann. setzen Sie min_z auf -8000.0 und max_z auf 0.0 für ein U-Boot, damit es nicht über den Meeresspiegel steigen kann. //--------------------------------- // Tastaturbelegung int key_direction; // dreht die Räder nach links/rechts standard: 1 int key_engine; // bewegt das Fahrzeug vorwärts/rückwärts standard: 2 int key_climb; // bewegt das Fahrzeug aufwärts/abwärts (Hubschrauber) int key_yaw; // dreht das Fahrzeug (Nase nach links/rechts) int key_pitch; // dreht das Fahrzeug (Nase hoch/runter) int key_roll; // dreht das Fahrzeug (linkes Ohr nach oben/unten) Die folgenden Tastenwerte sind zulässig : 0 = Funktion nicht belegt 1 = Cursor links/rechts 2 = Cursor nach oben/unten 3 = nach oben/unten blättern 4 = Ctrl+Cursor links/rechts 5 = Ctrl+Cursor nach oben/unten 6 = Ctrl+nach oben/unten blättern (Sie können negative Werte verwenden, um die Richtung der Kontrollen umzukehren) //--------------------------------- // Fahrzeugsteuerung float engine_force_on_road; // Vorwärtskraft des Motors, wenn die Räder den Boden berühren (0.0 bis 1.0e8) Dies wird für ein Auto verwendet, um eine Vorwärtskraft zu erzeugen. Wert 1.0 setzen float engine_force_in_air; // Vorwärtskraft des Motors, wenn die Räder den Boden nicht berühren (0.0 bis 1.0e8) Dies wird für ein Schiff oder ein Flugzeug verwendet, um eine Vorwärtskraft zu erzeugen. Wert 1.0 setzen float climbing_force; // Kraft nach oben mit key_climb (0.0 bis 1.0e8) Dies wird bei Hubschraubern/Drohnen verwendet, um eine nach oben gerichtete Kraft zu erzeugen. Wert 1.0 setzen float yaw_force; // Drehkraft mit key_yaw (0.0 bis 1.0e8) float pitch_force; // Drehkraft mit key_pitch (0.0 bis 1.0e8) float roll_force; // Drehkraft mit key_roll (0.0 bis 1.0e8) Diese 3 werden bei Schiffen oder Flugzeugen zum Drehen in alle Richtungen verwendet. Wert 1.0 setzen bool yaw_dependant_on_forward; // true = yaw Kraft hängt von der Vorwärtsbewegung ab, false = hängt nicht bool pitch_dependant_on_forward; // true = pitch Kraft hängt von der Vorwärtsbewegung ab, false = hängt nicht bool roll_dependant_on_forward; // true = roll Kraft hängt von der Vorwärtsbewegung ab, false = hängt nicht Setzen Sie diesen Wert auf true, um eine härtere Kontrolle zu erhalten: Sie können sich nur drehen, wenn Sie sich auch vorwärts bewegen. float direction_factor; // wie schnell sich die Räder beim Drücken der Taste drehen (1.0) (0.0 bis 1.0e8) float direction_max_angle; // maximaler Radwinkel (30.0 grad) (0.0 bis 90.0) Legt fest, wie schnell der Benutzer die Räder drehen lässt, wenn er die Richtungstaste drückt, und welchen maximalen Winkel die Räder haben können. float yaw_factor; // wie schnell sich das yaw-Ruder bewegt (0.0 bis 1.0e8) float yaw_max_angle; // maximaler yaw Winkel (30.0 grad) (0.0 bis 90.0) float pitch_factor; // wie schnell sich das pitch-Ruder bewegt (0.0 bis 1.0e8) float pitch_max_angle; // maximaler pitch Winkel (30.0 grad) (0.0 bis 90.0) float roll_factor; // wie schnell sich das roll-Ruder bewegt (0.0 bis 1.0e8) float roll_max_angle; // maximaler roll angle (30.0 grad) (0.0 bis 90.0) Legen Sie fest, wie schnell der Benutzer das Ruder oder die Klappen beim Drücken der Tasten drehen lässt, und welchen maximalen Winkel das Ruder/die Klappen haben können. float sliding_coef; // 0.0 bis 1.0 float sliding_z; // -0.05 (-32.767 bis 32.767) negatives z, wo die Räder Kraft ausüben, in Metern sliding_coef gibt an, wie rutschig die Reifen sind (0.0 = Asphalt bis 1.0 = Eis Schnee) sliding_z ist ein Wert in Metern, der angibt, auf welcher höhe die Reifenkraft auf den Boden einwirkt, Er kann 0.0 für völlige Stabilität betragen. Ein negativer Wert wie -0.05 kann dazu führen, dass das Auto in Kurven umkippt. float air_friction_coef; // (0.0 bis 1.0) float air_friction_vertical_coef; // (0.0 bis 1.0) air_friction_coef gibt an, wie dicht die Luft/das Wasser für ein Schiff/Flugzeug ist. Ein Wert von 0.0 fühlt sich wie im Weltraum an (vollständige Trägheit). Für eine bessere Kontrolle in den Kurven werden Sie einen Wert von etwa 0.5 wählen. air_friction_vertical_coef ist normalerweise 0.0 Ein Wert wie 1.0 blockiert vertikale Bewegungen, wenn das Fahrzeug nicht in Vorwärtsrichtung fährt. Dies kann für ein Fahrzeug verwendet werden, das ausschließlich vorwärts fliegt, wie ein Flugzeug, Gleiter, Deltaplane. float spring_force; // 1.3 Stoßdämpfer Kraft float spring_damping; // 0.005 Stoßdämpfer Gegenkraft (Dämpfung) Diese Parameter steuern die Radstoßdämpfer: die Kraft und die Gegenkraft. float keel_on_road; // (0.0 bis 1.0e8) float keel_in_air; // (0.0 bis 1.0e8) Diese Parameter wirken wie ein Schiffskiel, indem sie Gewicht unter das Fahrzeug bringen, um die Stabilität zu erhöhen. Der erste Parameter wird verwendet, wenn die Fahrzeugräder den Boden berühren, der zweite, wenn nicht. float stability_in_air; // 0.01 (0.0 bis 1.0) Verlangsamt die Rotationsgeschwindigkeit von Flugzeugen und Schiffen. Der Wert 0.0 bewirkt nichts, so dass das Fahrzeug wie ein Pendel hin und her pendelt. Ein kleiner Wert wie 0.01 verlangsamt dies. float yaw_z; // (0.0 bis 1.0e8) z Offset über dem Massenschwerpunkt, wo die yaw Kraft anzusetzen ist Wenn sich ein Flugzeug mit Hilfe des yaw dreht, wird das Flugzeug/Schiff auch ein wenig in Richtung roll gedreht. float forward_slowdown; // (-1.0 bis 1.0) verlangsamt die Vorwärtsbewegung des Fahrzeugs (-1.0 = keine Verlangsamung, 0.0 = Verlangsamung von 0.5%, 1.0 = Verlangsamung von 1%) float turning_slowdown; // (-1.0 bis 1.0) verlangsamt das Drehen des Fahrzeugs (-1.0 = keine Verlangsamung, 0.0 = Verlangsamung von 0.5%, 1.0 = Verlangsamung von 1%) //--------------------------------- // Optionen bool can_fly; // true = hebt die Schwerkraft in der Luft oder auf dem Meer auf, für fliegende und segelnde Fahrzeuge true für Fahrzeuge, die in der Luft bleiben können, ohne zu fallen, wie Flugzeuge, Schiffe und U-Boote. false für Autos, Hovercrafts oder alles, was auf den Boden fällt. bool apply_cubic_shape_in_air; // true = sanftes Drehen, wenn die Räder den Boden nicht berühren true wird für fliegende/segelnde Objekte empfohlen, um die Rotationssteuerung über die Tastatur zu erleichtern. in der Luft wird dann die rechteckige Masse des Fahrzeugs ignoriert und durch einen Würfel ersetzt. false für Autos bool block_fly_backwards; wenn true, kann man sich nicht rückwärts bewegen, wenn die Räder den Boden nicht berühren. bool auto_unblock; // true wenn true, wenn sich das Fahrzeug nicht bewegt und die Räder den Boden nicht berühren, gilt es als blockiert. Dann setzt eine automatische Entriegelung die Umdrehungen auf Null zurück. bool block_wheels_in_the_air; // die Räder eines Flugzeugs anhalten, wenn es in der Luft ist true = die Räder hören auf sich zu drehen wenn sie den Boden nicht mehr berühren (bei einem Flugzeug nach dem Start) //--------------------------------- // Mesh Räder ROTATING_MESH rotating_mesh[2 .. 32]; mesh 1 ist das Fahrzeug und kann nicht konfiguriert werden mesh 2 bis 32 können als Räder, Ruder oder andere bewegliche Teile konfiguriert werden. Für jeden Mesh geben Sie einen Typ und einen Radius an. Die Meshnummern müssen zusammenhängend sein, d. h. sie dürfen keine Lücken aufweisen. struct ROTATING_MESH { int typ; // Radtyp float radius; // in Metern } Die folgenden Arten von Radtyp sind möglich: 0 = nicht verwendet 1 = Vorderrad Links 2 = Vorderrad Mitte 3 = Vorderrad Rechts 4 = Hinterrad Links 5 = Hinterrad Mitte 6 = Hinterrad Rechts 7 = Segway links (oder Panzer) 8 = Segway rechts (oder Panzer) 9 = Auto-Lenkrad, Fahrrad-Viereck (gesteuert durch Richtung) (Radius auf 1.0 setzen !) 10 = Schiffsruder (gesteuert durch Yaw) (Radius auf 1.0 setzen !) 11 = Höhenruder (gesteuert durch Pitch) (Radius auf 1.0 setzen !) 12 = Rollruder (gesteuert durch Roll) (Radius auf 1.0 setzen !) Der angegebene Radius muss genau dem Radius der Meshräder entsprechen, in Metern, damit sich die Räder mit der richtigen Geschwindigkeit drehen. vector mesh_rotation[2 .. 32]; Für jeden Mesh 2 bis 32 können Sie eine konstante Nachdrehung angeben. der Vektor gibt die (x, y, z) Drehung in Grad an. Dies wird z. B. verwendet, um ein Fahrrad-Vorderteil um 20° zu neigen. float inclination_angle_direction; für ein Einrad oder ein Fahrrad: maximaler Neigungswinkel des Fahrzeugs beim Abbiegen in Kurven. float inclination_angle_height; für ein Einrad oder ein Segway: maximaler Neigungswinkel des Fahrzeugs beim Vorwärts- oder Rückwärtsfahren. //--------------------------------- }
Beispiele für Skripte finden Sie in den Demofahrzeugen im Shopping Center.
event vehicle_changed (vehicle_change e) { if (e.forward) { say ("go !"); } if (e.backward) { say ("STOP"); } }
Die Struktur "vehicle_change" ist definiert als :
struct vehicle_change { bool forward; // true wenn der Benutzer die Vorwärts-Taste gedrückt hat, um die Motordrehzahl zu erhöhen bool backward; // true wenn der Benutzer die Rückwärtstaste gedrückt hat, um die Motordrehzahl zu verringern bool left; // true wenn der Fahrer sich um 25° nach links wendet bool right; // true wenn der Fahrer sich um 25° nach rechts wendet }
Die Ereignisse collision_vehicle_avatar, collision_vehicle_vehicle und collision_vehicle_object werden ausgelöst, wenn Ihr Fahrzeug kollidiert, mit einem Avatar, mit einem anderen Fahrzeug, oder mit einem Objekt aus Material COLLISION.
Beispiel:
// in einem Fahrzeug event collision_vehicle_avatar () { key k = collision_avatar(); say ("collision_vehicle_avatar " + avatar_name(k) + " force = " + ftos(collision_force())); } // in einem Fahrzeug event collision_vehicle_vehicle () { key k = collision_avatar(); say ("collision_vehicle_vehicle " + avatar_name(k) + " force = " + ftos(collision_force())); } // in einem Fahrzeug oder einem Objekt aus Material 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();
Diese Funktion kann verwendet werden, um den kollidierenden Avatar zu bestimmen.
Für event COLLISION, COLLISION_VEHICLE_AVATAR, COLLISION_VEHICLE_VEHICLE, COLLISION_VEHICLE_OBJECT.
float collision_force ();
Mit dieser Funktion lässt sich die Kollisionskraft ermitteln.
Für event COLLISION_VEHICLE_AVATAR, COLLISION_VEHICLE_VEHICLE, COLLISION_VEHICLE_OBJECT.
int collision_object_id ();
Diese Funktion kann verwendet werden, um die ID des anderen Objekts (Fahrzeug oder Objekt) zu ermitteln.
Für event COLLISION_VEHICLE_VEHICLE, COLLISION_VEHICLE_OBJECT.
Mit animierten Meshe können Sie eine Animation auf einem Objekt ausführen, und das ohne Avatar.
Ein geriggter Mesh kann auf dem Standardskelett des männlichen oder weiblichen Avatars basieren oder ein benutzerdefiniertes Skelett haben. Aktivieren Sie im Modus Mesh Bearbeiten, Gelenke die entsprechende Option.
Ein am Avatar getragener Gegenstand muss immer sein eigenes benutzerdefiniertes Skelett haben wenn er seine eigenen Animationen per Skript ausführen will, unabhängig von den Animationen des Avatars.
void object_start_animation (string animation); void object_stop_animation (string animation);Startet oder stoppt eine Animation für ein Objekt.
bool object_is_animation_active (string animation);Prüft, ob für das angegebene Objekt gerade eine Animation läuft.
void display_menu (key avatar, string menu [,string menu2[,string menu3[,string menu4, ..]]]);Zeigt ein Benutzermenü an.
Beispiel:
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) + " hat volgendes menü geklickt : " + itos(menu_id)); }
void give_inventory (string item_name);gibt dem Inventar des Benutzers den Gegenstand mit dem gegebenen Namen.
string item_name (string previous_name [, int step]);listet alle Elemente auf, die sich im Skriptordner eines Objekts befinden.
string item_type (string item_name);liefert den Typ eines Elements.
Das Ereignis items_changed wird ausgelöst, wenn der Benutzer ein Element im Skriptordner des Objekts hinzufügt, ändert oder löscht.
event items_changed() { // Benutzer hat ein Element aus dem Skriptordner hinzugefügt/geändert/entfernt }
Beispiel:
// gibt alle Elemente außer denen vom Typ Skript : 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); } } }
Mit den folgenden Script-Befehlen können Sie einen Avatar automatisch an- und ausziehen. Sie ziehen Gegenstände, Texturen, Shapes und Animationen in das Inventar des Avatars und lassen ihn diese tragen oder ausziehen.
Wenn ein Avatar gerade erst auf dem Planeten angekommen ist und seine Kleidung noch nicht geladen ist, dann wird ein Skript, das Kleidungsbefehle ausführt, angehalten, bis alle seine Kleidungsstücke geladen sind. Ein Kleidungsskript kann daher bei einer langsamen Verbindung manchmal fast eine Minute lang pausieren, bevor es seine Ausführung fortsetzt. Dieser Mechanismus verhindert, dass dem Avatar falsche Kleidung angezogen wird.
void wear_object (key avatar, string item_name, bool permanent = false);
Ein Objekt automatisch von einem Avatar tragen lassen.
Das zu tragende Objekt muss sich im Ordner "Scripts" des Objektes befinden, das diesen Skript ausführt.
Das Objekt wird in dem Inventar des Avatars hinzugefügt, in den Ordner "Objecte", wenn permanent wahr ist, ansonsten in den Ordner "Temporär".
Ein Gegenstand in "Temporär" ist eingeschränkt : wenn er ausgezogen wird, wird er in den Ordner "Mülleimer" verschoben und der Avatar kann das Objekt danach nicht mehr bearbeiten oder wiederverwenden.
void unwear_object ();Entfernt das getragene Objekt, in dem dieses Skript läuft.
void unwear_object (key avatar, string item_name);Entfernt das getragene Objekt von einem Avatar.
string next_worn_object (key avatar, ref int snr);Listet alle getragenen Objekte auf.
Wenn ein automatisch getragenes Objekt entfernt wird, erhält das übergeordnete Skript, das wear_object() aufgerufen hat, ein Ereignis mit dem Avatarschlüssel und dem Namen des entfernten Objekts :
event detached (key avatar, string name) { }
void wear_texture (key avatar, string item_name, bool permanent = false);
Eine Textur automatisch von einem Avatar tragen lassen.
Die zu tragende Textur muss sich im Ordner "Scripts" des Objektes befinden, das diesen Skript ausführt.
Die Textur wird in dem Inventar des Avatars hinzugefügt, in den Ordner "Texturen", wenn permanent wahr ist, ansonsten in den Ordner "Temporär".
Eine Textur in "Temporär" ist eingeschränkt : wenn sie ausgezogen wird, wird sie in den Ordner "Mülleimer" verschoben und der Avatar kann die Textur danach nicht mehr wiederverwenden.
void unwear_texture (key avatar, string item_name, int body_part = -1, int layer = -1);
Entfernt die Textur von einem Avatar.
Die Zeichen '? (ersetzt 1 Zeichen) und '*' (ersetzt mehrere Zeichen) sind in item_name erlaubt, um mehrere Texturen zu entfernen.
body_part : 0=Kopf, 1=Brust, 2=Beine, 3=Augen, 4=Fingernägel, 5=Zehennägel, -1=Alles
layer : 0=Haut, 1=Tattoo, 2=Unterwäsche, 3=Kleidung, 4=Überkleidung, -1=Alles
void wear_shape (key avatar, string item_name, bool permanent = false);
Eine Shape automatisch von einem Avatar tragen lassen.
Die zu tragende Shape muss sich im Ordner "Scripts" des Objektes befinden, das diesen Skript ausführt.
Die Shape wird in dem Inventar des Avatars hinzugefügt, in den Ordner "Formen", wenn permanent wahr ist, ansonsten in den Ordner "Temporär".
Ein Shape in "Temporär" ist eingeschränkt : wenn sie ausgezogen wird, wird sie in den Ordner "Mülleimer" verschoben und der Avatar kann die Shape danach nicht mehr bearbeiten oder wiederverwenden.
void unwear_shape (key avatar, string item_name);
Entfernt die Shape von einem Avatar.
Die Zeichen '? (ersetzt 1 Zeichen) und '*' (ersetzt mehrere Zeichen) sind in item_name erlaubt, um mehrere Shapes zu entfernen.
Eine Animation automatisch von einem Avatar tragen lassen.
Die zu tragende Animation muss sich im Ordner "Scripts" des Objektes befinden, das diesen Skript ausführt.
Die Animation wird in dem Inventar des Avatars hinzugefügt, in den Ordner "Animationen", wenn permanent wahr ist, ansonsten in den Ordner "Temporär".
Eine Animation in "Temporär" ist eingeschränkt : wenn sie ausgezogen wird, wird sie in den Ordner "Mülleimer" verschoben und der Avatar kann die Animation danach nicht mehr bearbeiten oder wiederverwenden.
Die Animation wird auch in Meine Animationen hinzugefügt.
typ: 0=Stehen, 1=Laufen, 2=Rennen, 3=Fliegen, 4=Springen, 100-103 = dauerhaft, 1 bis 4 200-207 = Einzelperson, 1 bis 8 300-307 = Paar A, 1 bis 8 400-407 = Paar B, 1 bis 8Ein leerer item_name löscht die Animation.
Blockierungen können auf Avatare angewendet werden, die sich in einem schachtelförmigen Raum um ein gerezztes Objekt herum befinden.
struct space { vector min, max; } // Wendet Blockierungen auf einen Avatar an. // Der Avatar muss sich in der gleichen Domäne wie das Objekt befinden. // Wenn der Avatar-Parameter leer ist, gilt der Befehl für alle Avatare die sich im Raum befinden. // Optionen: // CAPTIVE : 0x0001 bedeutet, dass der Avatar den Raum nicht verlassen kann. // FLY : 0x0002 bedeutet, dass der Avatar nicht fliegen kann. // INVENTORY : 0x0008 blockiert inventory. // NAMES : 0x0010 versteckt Avatar-Namen in People und Conversation, und blockiert Profile außer Ihrem eigenen. // TELEPORT : 0x0020 bedeutet, dass der Avatar nicht teleportieren kann. // SENDCHAT : 0x0040 blockiert das Schreiben auf dem Chat (außer an getragene objekte mit event listen) // READCHAT : 0x0080 blockiert den Chat-Empfang (außer von say/say_to-Befehlen von getragenen Objekten) // CAMERA : 0x0200 bedeutet, dass der Avatar die Kamera nicht außerhalb des Raumes bewegen kann. // TOUCH : 0x0400 bedeutet, dass der vatar keine Objekte außerhalb des Boxbereichs berühren kann. // RADAR : 0x0800 bedeutet, dass der Avatar niemand im Fenster People sehen kann. // JUMP : 0x1000 bedeutet, dass der Avatar nicht springen kann. // Es können mehrere Optionen addiert werden. // 0 bedeutet keine Blockierungen. // Jede Skript-Rekompilierung oder Skriptfehler im Objekt entfernt auch alle Blockierungen. // Der Raum space kann bis zu 512m x 512m x 512m groß sein (-256.0 bis +256.0). void block_avatar_options (key avatar, int options, space space);
// Abrufen von Blockierungsoptionen für diesen Avatar int avatar_block_options (key avatar);
// Rufen Sie den nächsten Avatar mit Blockierungen ab. // Avatar beim ersten Aufruf löschen, einen null-Schlüssel bedeutet, dass kein weiterer Avatare blockiert sind. key next_avatar_blocked (key avatar);
void block_worn_object (blocking_parameters parameters);Blockiert Avatarfunktionen.
struct blocking_parameters { int options; float walking_speed; // in metern. wenn weniger als 3.2 m/s, dann ist kein Rennen erlaubt. float camera_distance; // in metern. float touch_distance; // in metern. float radar_distance; // in metern. 0.0 bis 256.0 float camera_angle; // Winkel in grad. 0.0 bis 180.0 uint fog_setting; // 0xKS_BBGGRR, Beispiel: 0xfe_000000 } // mit : // K = Grenze zwischen Nicht-Nebel und Nebel, von 0=fortschreitend bis F=hart, // S = Entfernung des Nebels, von 0=weit weg bis F=nah, // BBGGRR = rgb-Nebelfarbe. // options: // 0x0001 : blockiert die Menüs 'ausziehen' und 'eigenschaften' des getragenen Objekts. // 0x0002 : blockiert das Fliegen // 0x0004 : blockiert die Menüs 'tragen'/'ausziehen' von Häuten und Kleidungstexturen // 0x0008 : blockiert das Inventar // 0x0010 : versteckt Avatar-Namen in Leute und Conversation, und blockiert Profile außer Ihrem eigenen // 0x0020 : blockiert das Teleportieren // 0x0040 : blockiert das Schreiben auf dem Chat (außer an getragene objekte mit event listen) // 0x0080 : blockiert den Chat-Empfang (außer von say/say_to-Befehlen von getragenen Objekten) // 0x0100 : begrenzt die Schrittgeschwindigkeit, siehe .walking_speed // 0x0200 : begrenzt die Kamera Entfernung, siehe .camera_distance // 0x0400 : begrenzt die Zugelassene event touch Entfernung durch Linksklick, siehe .touch_distance // 0x0800 : begrenzt die Entfernung in der Avatare in Leute gesehen werden, siehe .radar_distance // 0x1000 : blockiert Springen // 0x2000 : fixiert die Kamera auf dem Knochen mGesicht vom Avatar // 0x4000 : begrenzt den horizontalen und verticalen Sichtwinkel der Kamera, z.B. .camera_angle = 45; // 0x8000 : macht Nebel, siehe .fog_setting // 0x10000 : macht meinen Avatar für mich unsichtbar (mein Schatten bleibt sichtbar)
Ein blockierter Avatar kann auf die Taste CheatOut im Profil klicken, um alle Blockierungen zu löschen, aber es wird dann in der Cheats-Liste in der Domain-Info hinzugefügt.
Textdateien können in den Skripten Ordner hinzugefügt und Zeile für Zeile gelesen werden.
// zählt die Anzahl der Zeilen einer Textdatei int count_lines (string item);
// gibt die Zeile n einer Textdatei zurück string read_line (string item, int line);
Beispiel:
// alle Zeilen einer Textdatei lesen 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); // Einfügen oder Aktualisieren von value vom index
store() wird verwendet, um einen Zeichenkettenwert auf einem permanenten Speicherort des Servers zu speichern, der mit der ID des Objekts verbunden ist.
Sie können maximal 10.000 Zeichenketten speichern, anschließend erhalten Sie einen Skriptfehler.
Die Zeichenketten werden beim Neustart des Skripts nicht gelöscht, der einzige Weg um alle Speicher zu löschen, ist, das Objekt zu löschen und ein neues zu rezzen.
Sie können einen einzelnen Zeichenkettenwert löschen, indem Sie eine leere Zeichenkette speichern.
Der Index darf nicht länger als 50 Zeichen sein und darf keine null Zeichen enthalten.
string fetch (string index); // wert abrufenfetch() wird verwendet, um einen zuvor mit store() gespeicherten Wert abzurufen.
string navigate (string index, int direction);liefert index Wert kleiner oder größer als der angegebene index.
Beispiel:
event start() { store (index => "hi-score", value => " 10 "); say (fetch(index => "hi-score")); // wird sagen, 10 }
Daten können dauerhaft im Inventar des Benutzers gespeichert werden, auch wenn der Benutzer sich neu logt oder wenn das Objekt ausgezogen und wieder getragen wurde.
void save_data_to_inventory (string index, string value);
den string 'value' im inventory auf dem PC vom avatar speichern
. nur für getragene Objekte
. Index darf maximal 50 Zeichen lang sein und darf keine null Zeichen enthalten.
. eine leere Zeichenkette als Wert löscht den Datensatz.
Sie können maximal 10_000 Datensätze speichern, weitere Datensätze werden stillschweigend ignoriert.
void load_data_from_inventory (string index, int direction = 0);lädt einen string, die zuvor im Inventar gespeichert wurde
-1 = Index kleiner als der angegebene Index suchen, 0 = angegebenen Index suchen, +1 = Index größer als angegebenen Index suchen.. liefert eine leere Zeichenkette index und Wert, wenn kein weiterer Index existiert.
event inventory_data_arrived (string index, string value) { say ("index = '" + index + "'"); say ("value = '" + value + "'"); }
Der Befehl generate_particles() erzeugt einen Partikelstreuer in der Mitte eines Meshes.
void generate_particles (particule_parameters p);
Beispiel:
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 Sekunden 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}; // weiß, 0% transparent p.life[0].end_color = {0xFFFFFFFF, 0xFFFFFFFF}; p.life[0].begin_size = {{0.2, 0.2}, {0.2, 0.2}}; // Größe 0.2 x 0.2 m p.life[0].end_size = {{0.2, 0.2}, {0.2, 0.2}}; p.life[0].orientation = 0; // immer vertikal ausgerichtet p.ambiant = true; p.sunlight = true; // p.texture = "brilliant"; // erfordert eine Textur namens "brilliant" im Ordner scripts generate_particles (p); }
Die Struktur particule_parameters enthält folgende Felder:
struct particule_parameters { int mesh_nr; // mesh nr, wo der Streuer erstellt wird. // Spritzen int nb_particles; // Anzahl der emittierten Partikel pro Spritze (Burst) int pause; // Pausenzeit zwischen den Spritzen, in Millisekunden int nb_bursts; // Anzahl der Spritzen, 0 bedeutet unendlich. // Partikelgeburt in der Box vector[2] box; // Partikel werden in zufallspositionen innerhalb der box erzeugt // Partikelgeburt im Sprüher float[2] direction_angle; // im horizontalen Winkelbereich nach außen sprühen float[2] height_angle; // im vertikalen Winkelbereich nach außen sprühen float radius; // Sprühabstand vom Zentrum, in dem die Partikel entstehen. // Partikel 3 Lebensdauern lifetime life[3]; // Jeder Partikel hat 3 aufeinanderfolgende Leben, siehe unten. bool dont_follow_emitter; // true = wenn sich der Mesh vom Streuer bewegt oder dreht, folgen die Partikel nicht. bool ambiant; // true = Partikel erhalten Umgebungslicht bool sunlight; // true = Partikel erhalten Sonnenlicht float smooth; // glanz 0.0 .. 0.99 0.0 = rauh, 0.99 = glatt float metal; // metal 0.0 .. 1.0 0.0 = nicht-metal, 1.0 = metal float translucid; // transluzid 0.0 .. 1.0 0.0 = nicht-transluzid, 1.0 = transluzid bool front; // false = Transparenz Priorität -3, true = Transparenz Priorität +3. int emissive_color; // Leuchtfarbe string(32) texture; // Name der Partikeltextur, muss im Ordner scripts hinzugefügt werden. int mode_uv; // wie Mesh u, v float u; float v; bool sort; // Partikel sortieren (schöneres Ergebnis für transparente Texturen, aber braucht mehr CPU!) // ketten modus int leash_id; // ID des zu verkettendes Objekts (ungleich Null aktiviert den Kettenmodus) int leash_mesh_nr; // Mesh nr des anderen Objekts, wo die Kette befestigt werden soll (1 .. 32) float leash_length; // Kettenlänge in Metern (maximal 256) float leash_stretch; // Streckungsfaktor (0..1), so dass sich die Partikel bei maximaler Länge ein wenig überlappen (0.0 = keine, 0.2=Kettenringe). bool leash_physics; // true = zieht den Avatar zurück, wenn er weiter weg ist als die Kettenlänge. }
Partikel können maximal 3 Leben haben, während derer sie ein anderes Verhalten aufweisen.
Die Struktur lifetime enthält die nachfolgenden Felder.
Wenn es zwei Felder gibt, können Sie eine untere und eine obere Grenze angeben, wobei für jedes Partikel ein Zufallswert zwischen beiden Grenzen gewählt wird.
struct lifetime { int[2] durations; // Partikellebensdauerbereich, in msecs (max. 1 Tag) float[2] begin_speed; // Anfangsgeschwindigkeitsbereich der Spritze float[2] end_speed; // Endgeschwindigkeitsbereich der Spritze vector[2] begin_velocity; // zusätzliche Anfangsgeschwindigkeit in m/s vector[2] end_velocity; // zusätzliche Endgeschwindigkeit in m/s vector[2] begin_acceleration; // zusätzliche Startbeschleunigung in m/s2 vector[2] end_acceleration; // zusätzliche Endbeschleunigung in m/s2 vector[2] begin_size; // Anfangspartikelgröße (Breite, Höhe) in Metern vector[2] end_size; // Endpartikelgröße (Breite, Höhe) in Metern int[2] begin_color; // Anfangsfarbe und Transparenz int[2] end_color; // Endfarbe und Transparenz int orientation; // 0=vertikal am Schirm, 1=in Richtung Geschwindigkeit, 2=horizontal in der Welt, 3=verkettet. }
Um Partikel zu stoppen, setzen Sie p.mesh_nr oder p.nb_particles auf Null.
Beispiel:
event start () { particule_parameters p; clear p; generate_particles (p); }
Hier ist ein Schneeskript mit 2 Leben: Zuerst sinkt die Flocke nach unten, dann bleibt sie eine Weile auf dem Boden liegen.
event start () { particule_parameters p; clear p; p.mesh_nr = 1; p.nb_particles = 1; p.pause = 200; p.emissive_color = 0xFFFFFF; // immer licht an p.smooth = 0.93; // glanz 0.0 .. 0.99 0.0 = rau, 0.99 = glatt p.box = {{-32.767, -32.767, 0.0}, {32.767, 32.767, 0.0}}; // kiste um das ganze 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}; // kleine seitengeschwindigkeit p.life[0].end_velocity = {{0.0, 0.0, -0.2}, {0.0, 0.0, -0.2}}; // fallgeschwindigkeit 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"; // benötigt eine textur "flocon" in dem script ordner generate_particles (p); }
void play_sound (string item_name, float volume = 1.0, // 0.0 bis 1.0 float radius = 20.0); // 0 bis 1024 mEinen Sound spielen.
Beispiele:
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 bis 1.0 float radius = 20.0); // 0 bis 1024 mEinen Sound in schleife spielen.
Beispiele:
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 ();Ambiant Sound stoppen
void media_play (key avatar, string url);
Spielt eine multimedia datei oder stream (mp3, mp4, wav, ..)
Leere oder illegale urls werden den Media stoppen.
Ein url das gerade schon spielt wird ignoriert.
Für ein Video Media müssen Sie ein rechteckigen Meshschirm bauen von ratio länge=4 höhe=3, Ambient und Sonne ausschalten, Farbe und Glüh auf 255,255,255 einstellen, und dann in das menü "Mesh / Diverse" gehen und die Option 'Video' anklicken.
Beispiel:
event touch() { key k = touched_avatar(); media_play (k, "http://dino.com/tina.mp4"); }
void media_pause (key avatar, bool on);Setzt ein Media in Pause oder setzt es fort.
Beispiele:
media_pause (k, on => true); // pause media_pause (k, on => false); // weiter
void media_seek (key avatar, int mode, float seconds);Ändert eine Media Position
. mode 0 : zur absoluten Position in Sekunden . mode 1 : zur relative Position in Sekunden (Sekunden können negativ sein) . mode 2 : relative vom Ende (Sekunden müssen negativ sein)
Beispiel:
media_seek (k, mode => 1, seconds => -5.0); // 5 secs zurück
void media_volume (key avatar, float volume); // 0.0 to 1.0Media lautstärke ändern
Beispiel:
media_volume (k, volume => 0.5); // halb laut
Sie können UTF-16-Zeichenketten mit maximal 1024 Zeichen mit einem externen tcp/ip-Server unter Verwendung der folgenden Befehle austauschen :
void tcp_open (string ip, int port); void tcp_close (); void tcp_send (string message);
und diese Skript-Ereignisse :
event tcp_received (string message) event tcp_disconnected ()
Zeichenketten werden mit einem 2-Byte-Präfix-Längenfeld gesendet.
Sie können nicht mehr als eine Zeichenkette pro Sekunde senden.
Im Falle des Ereignisses server_restart() geht die Verbindung verloren und muss erneut geöffnet werden.
Sie können den Hostnamen und Port des Planetenservers erhalten :
string server_name (); // max 256 Zeichen int server_udp_port(); // für planet, gewöhnlich 13000 int server_tcp_port(); // für web, gewöhnlich 80
Mit der Maus können Sie Bilder von Ihrer Festplatte ziehen, um sie auf einem Objekt in der Welt abzulegen.
Beispiel:
event image_dropped () { set_mesh_texture (1, ""); // Bild auf Mesh 1 anwenden }
Die mesh Anzeige sollte ein 4/3-Format haben (Breite = 4, Höhe = 3).
Bilder werden automatisch in der Größe angepasst und mit einem transparenten Rand zentriert.
Der Befehl set_mesh_texture(mesh_nr, ""); hat nur eine wirkung :
. für Weltobjekte (nicht für getragene Objekte), . für Befehle (nicht für Bewegungsbatches), . nur im Ereignis image_dropped.
In allen anderen Fällen stellt es die Standardtextur wieder her.
Innerhalb eines Ereignisses image_dropped sind die folgenden Aufrufe erlaubt:
key touched_avatar (); // wer zieht das Bild int touched_mesh_nr (); // auf welchen Mesh world_position touched_world_position (); // auf welche Welt Position vector touched_mesh_position (); // auf welche Mesh Position
void show_money_dialog (key avatar);Zeigt ein Geld-Dialogfenster für diesen Avatar an.
string money_balance (key avatar);Gibt den Geldsaldo des Benutzers zurück, Beispiel "+124.50"
int give_activity_money (key beneficiary);Überträgt tägliches Planetenaktivitäts-Bonusgeld auf das Konto des Benutzers.
void ask_money_payment (key customer, int amount, string comment);
Fordert den Kunden auf, den Betrag an den Skripteigentümer zu zahlen.
Der Betrag muss zwischen 1 und 999_999 liegen.
Eine 5%ige Steuer wird von dem Betrag abgezogen, wenn das Geld von jemanden anders kommt.
Die Funktion erzeugt das Ereignis money_received, wenn der Kunde zahlt.
event money_received (key customer, int amount, string comment);Dieses Ereignis wird erzeugt, wenn der Kunde gerade den Betrag an den Skripteigentümer gezahlt hat.
Beispiel:
// Bezahlscript 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);
Überträgt Geld vom Skriptbesitzer an den Begünstigten.
In der Lasche Zugriff des Objekts müssen Sie die Option "Geld verteilen" aktivieren.
Ein leerer Begünstigter überweist Geld an die Planetenzentralbank.
Der Betrag muss zwischen 1 und 999_999 liegen.
Die Funktion gibt einen Fehlercode zurück:
0 Überweisung war erfolgreich -3 illegaler Betrag, muss zwischen 1 und 999_999 liegen -4 unzureichende Deckung -5 im getragenen Objekt nicht erlaubt. -6 dem Objekt ist nicht erlaubt Geld zu verteilen, siehe Lasche Zugriff
int area_bonus (int amount);
Diese Funktion erhöht die Maximal erlaubten kosten eines Area.
Um sie zu verwenden, rezzen Sie das Objekt auf die Area, die Sie erhöhen möchten.
Sie erhalten 1 zusätzlichen Landkosten pro 10ρ Geld, bis zu einer harten Grenze von 9000 Landkosten.
Die Funktion funktioniert nur in einem Ereignis Touch oder Menu_Selected und nur, wenn der Skriptbesitzer die Person ist, die das Objekt anklickt.
Das Konto des klickenden Avatars wird belastet.
Die Funktion gibt einen Fehlercode zurück:
0 ok -3 illegaler Betrag, muss zwischen 20 und 999_999 liegen -4 unzureichende Deckung -5 im getragenen Objekt nicht erlaubt. -6 illegale Area (nicht im Besitz). -7 Kosten (Bereich ist bereits bei maximalen Kosten 9000). -8 nur im Ereignis touch oder menu_selected. -9 Klickender Avatar muss Objektbesitzer sein.
pid get_planet_id ();
Ermittelt die eindeutige Planeten-ID (pid) dieses Planeten.
Eine pid ist definiert als:
typedef int[2] pid;
Beispiel:
event start() { pid p; p = get_planet_id (); say ("planet = {" + itos(p[0]) + ", " + itos(p[1]) + "}"); }
bool same_pid (pid a, pid b);
Prüft, ob zwei Planeten-IDs identisch sind.
void send_message_to_planet (pid planet, int object_id, string message);
Sendet eine Nachricht an ein Objekt auf einem bestimmten Planeten, wo sie ein Ereignis planet_message_received auslöst.
void broadcast_message_to_planet (pid planet, string script_name, string message);
Sendet eine Nachricht an alle Skripte mit dem angegebenen Namen auf einem bestimmten Planeten, wo sie ein Ereignis planet_message_received auslöst.
Dieses Ereignis wird ausgelöst, wenn eine Nachricht von einem Objekt auf einem anderen (oder demselben) Planeten empfangen wurde.
Innerhalb des Ereignisses kann die Funktion sender_object_owner() verwendet werden, um den Besitzer des geskripteten Objekts zu ermitteln, das die Nachricht gesendet hat.
Beispiel:
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();
Ermittelt den Besitzer des geskripteten Objekts, das die Nachricht gesendet hat.
Kann nur im Ereignis planet_message_received verwendet werden.
void teleport_to_planet2 (key k, pid planet); void teleport_to_planet2 (key k, pid planet, int domain);
Teleportiert Avatar k zu einem Planeten und optional zu einer Domäne.
Die Domäne muss in der öffentlichen Suche sichtbar sein.
Das Skriptobjekt muss mindestens den Rang security officer auf der Ursprungsdomäne haben.
Um den Kampfmodus einzustellen, wählen Sie das Menü Werkzeuge / Einstellungen : aktivieren Sie den Kampfmodus über die Taste C oder F6, wählen Sie aus, ob man die ganze Zeit rennt, und wählen Sie die Mausgeschwindigkeit.
Um den Kampfmodus zu aktivieren, drücken Sie F6 oder C.
void set_arm_range (float distance);
Legt die Reichweite der ausgewählten Waffe in Metern fest.
void set_arm_power (int power);
Legt die Stärke (die Menge an Schaden) fest, die die ausgewählte Waffe zufügt.
event shot (key victim, int power)
Dieses Ereignis wird aufgerufen, wenn wir ein Opfer angeschossen haben.
event damage (key shooter, int power)
Dieses Ereignis wird aufgerufen, wenn wir angeschossen wurden.
Beispiel:
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 = Objekte erkennen, 2 = Avatare erkennen, 3 = beides. world_position origin; vector direction; // Richtungseinheitsvektor, zum Beispiel {0.0, 0.0, -1.0}, der nach unten zeigt float max_distance; // in Metern (0.001 bis 100.0) float radius; // Strahlenradius, in Metern, (0.0 bis 10.0) // output int typ; // 0 = keine Kollision, 1 = kollidierte mit Objekt, 2 = kollidierte mit Avatar. world_position position; // Kollisionsposition float distance; // in Metern (kleiner als max_distance im Falle einer Kollision) vector normal; // Kollisionsnormalvektor. z.B.: {0.0, 0.0, 1.0} für die Kollision mit dem Boden. // output for typ 1 (object) : int object_id; // id des kollidierten Objekts int mesh_nr; // nr des kollidierten Meshes (1 .. 32) vector mesh_position; // lokale Position des vom Strahl getroffenen Meshes // output for typ 2 (avatar) : key avatar; // Schlüssel des kollidierten Avatars (wenn typ == 2) }
bool cast_ray (ref ray_casting r);
Wirft einen unsichtbaren Strahl ab und erkennt das erste nicht-phantom Objekt oder Avatar, den er berührt.
Sie müssen die 'Input'-Felder vor dem Aufruf der Funktion ausfüllen und die Ergebnisse in den 'Output'-Feldern ablesen.
Die Funktion gibt true zurück, wenn ein Objekt oder Avatar berührt wird, sonst false.
Beispiel:
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}; // nach unten 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 ("keine Kollision"); }
void earthquake (int intensity, // 0 bis 100 float duration); // 0.0 bis 30.0 sek
Löst ein Erdbeben von bestimmter Stärke und Dauer aus. Sie müssen Land Owner sein, um diese Funktion nutzen zu können.
string itos (int value, int width=0, string filler=" "); // Beispiel: itos(23, 5, "0") == "00023" string ftos (float value, int width=0, int decimals = 3); // Beispiel: ftos(23.2, 5) == " 23.2" string btos (bool value, int width=0); // Beispiel: btos(b) == "true" bool stob (string str); // Beispiel: stob(" true ") == true int stoi (string str); // Beispiel: stoi("-23") == -23 float stof (sring str); // Beispiel: stof(" 13.7 ") == 13.699 float itof (int value); int ftoi (float value); // truncates
int len (string value); // Beispiel: len("abc") == 3 string chr (int c1, int c2, int c3, ..., int c16); // Beispiel: chr(65,66,67) == "ABC" int asc (string value, int index=1); // Beispiel: asc("AB") == 65 asc("ABC",2) == 66 string left (string value, int count); // Beispiel: left("ABCD",2) == "AB" string right (string value, int count); // Beispiel: right("ABCD",2) == "CD" string mid (string value, int index, int count=); // Beispiel: mid("ABCDEF",2,3) == "BCD" mid("ABCDEF",5) == "EF" int pos (string phrase, string word); // Beispiel: pos("ABCDEF","CD") == 3 pos("ABCDEF","X") == 0 string dup (string value, int count); // Beispiel: dup("-*",3) == "-*-*-*" string upper (string value); // Akzente entfernen und in Großbuchstaben umwandeln string lower (string value); // Akzente entfernen und in Kleinbuchstaben umwandeln string trim (string value); // vor- und nachlaufende Leerzeichen entfernen string ltrim (string value); // führende Leerzeichen entfernen string rtrim (string value); // Entfernen von nachlaufenden Leerzeichen string resolve_icons (string value); // wandelt Sequenzen wie :) in Icon-Codes um
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=Montag, 7=Sonntag) date_time add_seconds (date_time date, int seconds); int area_time_offset (); // Sekunden, die zur gmt-Zeit addiert werden müssen, um die Ortszeit zu erhalten. int nb_days_since_1901 (date_time date); // nb Tage zwischen 1.1.1901 und Datum
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 (); // Wert zwischen 0 inklusive und 1 exklusive float fabs (float value); float sin (float angle); // Winkel in Grad float cos (float angle); // Winkel in Grad float atan2 (float y, float x); // Ergebniswinkel in Grad 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);
Einige Skriptbefehle, die auf Avatare einwirken, erfordern eine Erlaubnis, da sie sonst keine Wirkung haben.
Insbesondere die folgenden Befehle benötigen eine Erlaubnis:
sit, start/stop_animation, wear/unwear_xxx, block_avatar_options, display_menu, media_xxx, show_money_dialog, set_avatar_world_position, teleport_to_planet.
Die Erlaubnis wird in 3 Fällen erteilt:
a) Wenn Avatar A ein Ereignis auslöst (z.B. A klickt, event touch), dann kann das Skript auf A einwirken.
b) Wenn das Objekt dem Avatar A gehört oder von A getragen wird, kann das Skript auf A einwirken.
c) wenn das Objekt dem Avatar A gehört oder von A getragen wird, und A mindestens security officer auf der Domäne ist, dann kann das Skript auf alle Avatare einwirken.
Wenn das Ereignis nicht von A ausgelöst wurde (z.B. ein event start oder timer), A auch nicht Eigentümer des Objekts ist, und der Eigentümer des Objekts auch nicht mindestens security officer ist, dann hat der Skriptbefehl keine Wirkung auf A.
// Türskript 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}); }
// Türskript mit dem Schließen der Tür nach 10 Sekunden 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; }
// Lampenscript 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); }
Die Skriptkosten hängen von der Anzahl der Befehle, von der Größe der globalen Variablen, und von der Speicherung von Zeichenkettenliteralen ab.
Lokale Variablen werden nicht einbezogen.
Im Falle eines Fehlers senden Sie eine Beschreibung an: marcsamu@hotmail.com