Wie man Skripte schreibt

Inhaltsverzeichnis



1. Schreiben von Skripten

Haben Sie noch nie geskriptet?
Klicken Sie auf Skriptkurs, um die Grundlagen des Programmierens zu erlernen.

1. Kompilierung

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.

2. Beschreibung der Skriptsprache

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: * / % + - << >> == != < > <= >= && || & | ^

3. Ausführungsgeschwindigkeit von Skripten

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.

2. Ereignisse

1. Start

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!");
  }

2. Touch

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);

3. Collision

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.

4. Listen

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.
"*" ersetzt viele Zeichen, "?" ersetzt ein Zeichen.

Beispiel: filter "!*" erfasst nur Chatzeilen, die mit "!" beginnen, wie "!start" und "!stop".

5. Timer

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
  }

6. Message_Received

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.

7. Server Restart

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.

2. Konversation

1. Say

  void say (string value);
Anzeige von Text im Chat in einer Entfernung von 20m
  // Beispiel:
  event start ()
  {
    say ("hallo, ich starte !");
  }

2. say_to

  void say_to (key avatar, string value);
Das Gleiche wie say, aber für einen einzelnen Avatar.

3. Ikonen anzeigen

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);
  }

4. Bilder anzeigen

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") + " :)");
  }

5. Schreiben in verschiedenen Schriftarten und Farben

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");
  }

3. Mesh

1. Set Mesh Active

  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
  }

2. Set Mesh Position

  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});
  }

3. Set Mesh Rotation

  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});
  }

4. Set Mesh Color

  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);
  }

5. Set Mesh Transparency

  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);
  }

6. Set Mesh Light

  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);
  }

7. Set Mesh Lightning

  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);
  }

8. Set Mesh Glow

  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);
  }

9. Set Mesh Uv

  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.

10. Set Mesh Texture

  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");
  }

4. Objekt

1. object_id

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.

2. is_worn

bool is_worn ();
gibt true zurück wenn das aktuelle Objekt getragen wird, false wenn es auf dem Land ist.
(tatsächlich hat ein getragenes Objekt eine negative object_id, eines auf Land eine positive)

3. object_name

string object_name ([int object_id]);
gibt den Namen des Objekts zurück (max 32 Zeichen)

4. set_object_name

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.
für ein World-rezzed-Objekt, ist die Namensänderung dauerhaft.

5. object_owner

key object_owner ([int object_id]);
gibt den Besitzer des Objekts zurück.

6. object_owner_date

string object_owner_date ([int object_id]);
gibt ein Datum im Format "JJJJMMTT" zurück

7. object_nb_meshes

int object_nb_meshes();
gibt die Anzahl der Meshes des Objekts zurück.

8. domain_id

int domain_id();
gibt den Domain-ID zurück wo das Objekt sich befindet.

9. domain_name

string domain_name();
gibt den Domain-Namen zurück wo das Objekt sich befindet.

10. domain_adult

bool domain_adult();

prüft ob sich das Objekt auf einem erwachsenen Domain befindet.

11. object_access

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.

12. object_world_position

world_position object_world_position (int object_id);
gibt die Weltposition des Objekts zurück.

13. object_rotation

vector object_rotation (int object_id);
gibt die Rotation des Objekts zurück.

14. set_object_world_position

int set_object_world_position (int object_id, world_position position);
bewegt das Objekt
gibt 0 zurück, wenn OK, oder einen der folgenden negativen Werte:
         -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.

15. set_object_rotation

void set_object_rotation (int object_id, vector rotation);
dreht das Objekt

16. rezz_object_relative/absolute

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).

17. clone_object

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).

18. parent_object_id

int parent_object_id ();
gibt eine positive ID des übergeordneten Objekts zurück, das dieses Objekt gerezzt, geclont oder getragen hat,
oder -1, wenn es nicht von einem Skript gerezzt oder getragen wurde,
oder -2, wenn die ID jetzt ungültig ist, weil sich der Benutzer neu gelogt hat.
Diese Funktion sollte nur im startereignis verwendet werden, da das ElternObjekt schnell ungültig werden kann.

19. delete_object

void delete_object();
löscht das Objekt, das dieses Skript ausführt.

20. event child_died

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 ();
  }

21. next_object_of_area

int next_object_of_area (int area_x, int area_y, ref int snr);
listet alle Objekte im Area auf.
snr muss auf 0 gesetzt werden und wird bei jedem Aufruf geändert.
gibt die ID des nächsten Objekts in diesem Bereich zurück, oder 0 wenn es keine Objekte mehr gibt.
Wenn sich das Skriptobjekt bewegt, ist die Funktion nicht zuverlässig.

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));
    }
  }

22. Bewegungsbatches

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.

1. begin_move, end_move

Alle Befehle eines Batches müssen zwischen :

  void begin_move ();
  void end_move ();

2. move_job

Innerhalb eines Batches können Sie einen oder mehrere Jobs angeben, die jeweils so beginnen müssen :
  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.

3. job_duration

Zwischen den Befehlen können Sie eine Dauer angeben, um ein Überblenden zwischen dem vorherigen und späteren Zustand zu bewirken:
  void job_duration (int duration);    // Die Dauer muss >= 16 Millisekunden sein.

4. stop_move

Um einen laufenden Batch zu stoppen, rufen Sie :
  void stop_move ();
Einige Regeln:
. wenn Sie einen direkten Befehl außerhalb des Batchs angeben, stoppt der Server zuerst den Batch.
Der Befehl set_object_world_position() kann nur im ersten Job eines Batchs angegeben werden.
. ein sich wiederholender Job muss mindestens einen Befehl job_duration haben.
. ein sich nicht wiederholender Job darf am Ende keinen job_duration-Befehl haben.
. Batches werden in Reihenfolge ausgeführt.
. einer sich wiederholende Batch wird nicht mehr wiederholt, wenn eine weitere nachfolgende Batch gesendet wird.

Weitere Befehle :

5. end_move2

  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.

6. nb_queued_moves

 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.

7. rest_move_duration

 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 ();
  }

5. Avatar

1. avatar_online

  bool avatar_online (key k);
Liefert true, wenn ein Avatar online ist, false, wenn nicht.

2. avatar_name

  string avatar_name (key k);
Liefert einen aktuellen vollständigen Avatar-Namen (maximal 71 Zeichen).

3. avatar_rank

  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.

4. has_rank

  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.

5. set_avatar_rank

  void set_avatar_rank (key k, int rank);
Ändert den Rang eines Avatars, wenn Sie Rechte dafür haben.

6. avatar_gender

  int avatar_gender (key k);
Gibt ein Avatar-Geschlecht zurück : 0=male, 1=female.

7. avatar_adult

  int avatar_adult (key k);
Gibt den Erwachsenen Status des Avatars wieder : 0=minderjärig, 1=Erwachsen, -1=key ungütltig.

8. avatar_language

  int avatar_language (key k);
Gibt die Sprache des Avatars zurück (0 = französisch, 1 = englisch, 2 = deutsch, -1 = key ungütltig)

9. avatar_experience

  int avatar_experience (key k);
Gibt die Avatar experience zurück, oder -1 falls key unbekannt ist.

10. avatar_timezone

  int avatar_timezone (key k);
Gibt die Avatar timezone zurück, in Stunden, von -12 bis +12.

11. avatar_title

  string avatar_title (key k);
Gibt den Avatar title zurück, maximum 24 Zeichen.

12. avatar_world_position

  world_position avatar_world_position (key k);
Liefert eine Avatar-Weltposition (z ist 0, wenn man auf dem Boden in Höhe 0 steht).

13. avatar_z_rotation

  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));
  }

14. set_avatar_world_position_and_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);
  }

15. teleport_to_planet

  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.

16. next_avatar

key next_avatar (ref int snr);
listet nacheinander alle Avatare in einem Radius von 256 Metern auf.
snr muss auf 0 initialisiert werden, es wird bei jedem Aufruf geändert.
Wenn snr nach dem Anruf 0 ist, gibt es keine Avatare mehr.

Beispiel:

  event touch()
  {
    int snr = 0;
    for (;;)
    {
      key avatar = next_avatar (ref snr);
      if (snr == 0)
        break;

      say (avatar_name (avatar));
    }
  }

17. event owner_login

  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.

18. avatars_online_count

  int avatars_online_count();

berechnet die Anzahl der Avatare, die gerade auf diesem Planeten online sind (0 bis 1024).

19. avatar_key

  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.

6. Sitzen und Animationen

1. is_sitting

bool is_sitting (key avatar);
Testet, ob ein Avatar auf diesem Objekt sitzt.

2. sit

bool sit (int mesh_nr, vector position, vector rotation, key avatar);
Setzt einen Avatar mit Position/Rotation auf die mesh_nr dieses Objekts.
Dies hat Vorrang vor jeder vorherigen Sitzung und hebt alle vorherigen Animationen auf.
Das Skript muss auf der gleichen Domäne laufen wo der Avatar steht, oder es gibt false zurück.

3. unsit

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.

4. start/stop_animation

void start_animation (string animation, key avatar);
void stop_animation (string animation, key avatar);
Startet oder stoppt eine Animation.
Eine BVH Animation muss in dem Ordner Skripte vom Objekt vorhanden sein.

5. is_animation_active

bool is_animation_active (string animation, key avatar);
Prüft, ob diese Animation aktuell auf dem angegebenen Avatar läuft.

6. override_animation

void override_animation (int typ, string animation);
Ersetzen von Standardanimationen (Stehen, Gehen, Laufen, Fliegen, Springen)
nur für ein getragenes Objekt.
typ : 0=Stehen, 1=Gehen, 2=Laufen, 3=Fliegen, 4=Springen
Verwenden Sie eine leere Zeichenkette für animation, um das Ersetzen aufzuheben.
// 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);
    }
  }

7. event click_avatar

  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.

8. get_sitter

  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);
        }
      }
    }
  }

9. event avatar_unsits

  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.

10. set_camera_stability

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)

7. Fahrzeuge

Um ein Fahrzeug zu fahren, müssen Sie :
1) den Avatar auf das Fahrzeug setzen, wie auf eine Couch,
2) optional die Kamerastabilität einstellen (siehe oben),
3) control_vehicle() mit einer Reihe von Parametern aufrufen.

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.

1. control_vehicle

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.

2. event vehicle_changed

Sie können das Ereignis "vehicle_changed" behandeln, um auf bestimmte Aktionen zu reagieren:
  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
  }

3. Fahrzeugkollisionen

1. Ereignisse collision_vehicle_avatar, collision_vehicle_vehicle, collision_vehicle_object

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));
}

2. collision_avatar

  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.

3. collision_force

  float collision_force ();

Mit dieser Funktion lässt sich die Kollisionskraft ermitteln.

Für event COLLISION_VEHICLE_AVATAR, COLLISION_VEHICLE_VEHICLE, COLLISION_VEHICLE_OBJECT.

4. collision_object_id

  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.

8. Animierte Meshe

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.

1. object_start/stop_animation

  void object_start_animation (string animation);
  void object_stop_animation (string animation);
Startet oder stoppt eine Animation für ein Objekt.
Im Skriptordner des Objekts muss eine BVH-Animation vorhanden sein.
Es können maximal 4 Animationen gleichzeitig laufen.

2. object_is_animation_active

  bool object_is_animation_active (string animation);
Prüft, ob für das angegebene Objekt gerade eine Animation läuft.

9. Menüs

1. display_menu

void display_menu (key avatar, string menu [,string menu2[,string menu3[,string menu4, ..]]]);
Zeigt ein Benutzermenü an.
Das Menü kann max 3 niveaux, max 20 Zeilen per niveau, max 1024 Zeichen haben.
Falls das Menü länger als 1024 Zeichen ist, teilen Sie es.
Wenn ein Benutzer eine Menüzeile auswählt bekomt das Skript ein Ereignis menu_selected.

2. event menu_selected

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));
  }

10. Inventar

1. give_inventory

void give_inventory (string item_name);
gibt dem Inventar des Benutzers den Gegenstand mit dem gegebenen Namen.
Diese Funktion ist nur innerhalb von Ereignissen TOUCH, MENU_SELECTED, COLLISION oder MONEY_RECEIVED erlaubt.

2. item_name

string item_name (string previous_name [, int step]);
listet alle Elemente auf, die sich im Skriptordner eines Objekts befinden.
gibt den Namen des nächsten Elements zurück, "", wenn keine mehr.
step kann +1 sein, um vorwärts zu blättern, oder -1, um rückwärts zu blättern.

3. item_type

string item_type (string item_name);
liefert den Typ eines Elements.
gibt eines von "TEX", "OBJ", "SCR", "BVH", "SHP", "WAV" oder "" falls item_name nicht existiert.

4. event items_changed

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);
      }
    }
  }

11. Ankleiden

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.

1. Objekte anziehen

1. wear_object

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.

2. unwear_object

void unwear_object ();
Entfernt das getragene Objekt, in dem dieses Skript läuft.
Nur zulässig, wenn dieses Skript in einem getragenen Objekt läuft.

3. unwear_object()

void unwear_object (key avatar, string item_name);
Entfernt das getragene Objekt von einem Avatar.
Die Zeichen '? (ersetzt 1 Zeichen) und '*' (ersetzt mehrere Zeichen) sind in item_name erlaubt, um mehrere Objekte zu entfernen.

4. next_worn_object

string next_worn_object (key avatar, ref int snr);
Listet alle getragenen Objekte auf.
Gibt den Namen des nächsten getragenen Objekts zurück (max. 32 Zeichen).
snr muss auf 0 initialisiert werden und wird bei jedem Aufruf geändert. Es wird auf 0 zurückgesetzt, wenn es keine weiteren getragenen Objekte gibt.

5. event detached

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)
  {
  }

2. Texturen anziehen

1. wear_texture

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.

2. unwear_texture

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

3. Shapes anziehen

1. wear_shape

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.

2. unwear_shape

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.

4. Animationen anziehen

1. wear_override_animation

void wear_override_animation (key avatar, int typ, string item_name, bool permanent = false);

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 8
Ein leerer item_name löscht die Animation.

12. Blockierungen

a) Blockierungen durch Objekte in der Welt

Blockierungen können auf Avatare angewendet werden, die sich in einem schachtelförmigen Raum um ein gerezztes Objekt herum befinden.

1. block_avatar_options

  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);

2. avatar_block_options

  // Abrufen von Blockierungsoptionen für diesen Avatar
  int avatar_block_options (key avatar);

3. next_avatar_blocked

  // 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);

b) Blockierungen durch getragene Objekte

1. block_worn_object

void block_worn_object (blocking_parameters parameters);
Blockiert Avatarfunktionen.
Nur für getragene Objekte zulässig.
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.

13. Textdateien

Textdateien können in den Skripten Ordner hinzugefügt und Zeile für Zeile gelesen werden.

1. count_lines

  // zählt die Anzahl der Zeilen einer Textdatei
  int count_lines (string item);

2. read_line

  // 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);
    }
  }

14. Permanente Speicherung

a) speicherung für Objekten auf dem Land

1. store

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.

2. fetch

string fetch (string index);                // wert abrufen
fetch() wird verwendet, um einen zuvor mit store() gespeicherten Wert abzurufen.
Wenn es keinen gab, wird eine leere Zeichenkette zurückgegeben.

3. navigate

string navigate (string index, int direction);
liefert index Wert kleiner oder größer als der angegebene index.
direction kann -1 (kleiner) oder +1 (größer) sein.
Gibt einen leere Zeichenkette zurück, wenn kein weiterer Index vorhanden ist.

Beispiel:

  event start()
  {
    store (index => "hi-score", value => " 10 ");
    say (fetch(index => "hi-score"));   // wird sagen, 10
  }

b) speicherung für getragene Objekte

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.

1. save_data_to_inventory

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.

2. load_data_from_inventory

void load_data_from_inventory (string index, int direction = 0);
lädt einen string, die zuvor im Inventar gespeichert wurde
. nur für getragene Objekte
. 'direction' kann foldende Werte haben :
    -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.
. Wert wird im folgenden Ereignis zurückgegeben :

3. event inventory_data_arrived

    event inventory_data_arrived (string index, string value)
    {
      say ("index = '" + index + "'");
      say ("value = '" + value + "'");
    }

15. Partikel

Der Befehl generate_particles() erzeugt einen Partikelstreuer in der Mitte eines Meshes.

1. generate_particles

  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);
}

16. Sound

1. play_sound

  void play_sound (string item_name,
                   float  volume = 1.0,     // 0.0 bis 1.0
                   float  radius = 20.0);   // 0 bis 1024 m
Einen Sound spielen.
Maximum 16 Sounds können pro Minute gespielt werden, weitere Sounds werden ignoriert.
Sound files müssen .wav 44.1KHz PCM 16-bit und maximum 90 Sekunden lang sein sonst werden sie abgekürzt. Sie können Sounddateien mithilfe der kostenlosen Software https://audacity.fr/ in dieses Format umwandeln

Beispiele:

  play_sound ("ding");
  play_sound ("ding", volume => 1.0);
  play_sound ("ding", volume => 1.0, radius => 20.0);

2. start_ambiant_sound

  void start_ambiant_sound (string item_name,
                            float  volume = 1.0,     // 0.0 bis 1.0
                            float  radius = 20.0);   // 0 bis 1024 m
Einen Sound in schleife spielen.
Sound files müssen .wav 44.1KHz PCM 16-bit und maximum 90 Sekunden lang sein sonst werden sie abgekürzt.
Nur ein Ambiant Sound per Objekt ist erlaubt, frühere Sounds werden gestoppt.

Beispiele:

  start_ambiant_sound ("sea");
  start_ambiant_sound ("sea", volume => 1.0);
  start_ambiant_sound ("sea", volume => 1.0, radius => 20.0);

3. stop_ambiant_sound

  void stop_ambiant_sound ();
Ambiant Sound stoppen

17. Media

1. media_play

  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");
  }

2. media_pause

  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

3. media_seek

  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

4. media_volume

  void media_volume (key avatar, float volume);   // 0.0 to 1.0
Media lautstärke ändern
Dies ändert auch der Wert in tools/sounds

Beispiel:

  media_volume (k, volume => 0.5);  // halb laut

18. Tcpip Aufrufe

1. tcp_open/close/send

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);

2. tcp_received/disconnected

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.

3. server_name/udp_port/tcp_port

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

19. Ziehen und Ablegen

1. event image_dropped

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

20. Geld

1. show_money_dialog

void show_money_dialog (key avatar);
Zeigt ein Geld-Dialogfenster für diesen Avatar an.

2. money_balance

string money_balance (key avatar);
Gibt den Geldsaldo des Benutzers zurück, Beispiel "+124.50"

3. give_activity_money

int give_activity_money (key beneficiary);
Überträgt tägliches Planetenaktivitäts-Bonusgeld auf das Konto des Benutzers.
Gibt den übertragenen Betrag zurück, der 0 sein kann.

4. ask_money_payment

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.

5. event money_received

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);
  }

6. give_money

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

7. area_bonus

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.

21. Interplanetare Kommunikation

1. get_planet_id

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]) + "}");
  }

2. same_pid

bool same_pid (pid a, pid b);

Prüft, ob zwei Planeten-IDs identisch sind.

3. send_message_to_planet

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.

4. broadcast_message_to_planet

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.

5. event planet_message_received

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 + "'");
}

6. sender_object_owner

key sender_object_owner();

Ermittelt den Besitzer des geskripteten Objekts, das die Nachricht gesendet hat.
Kann nur im Ereignis planet_message_received verwendet werden.

7. teleport_to_planet2

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.

22. Kampfmodus

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.

1. set_arm_range

void set_arm_range (float distance);

Legt die Reichweite der ausgewählten Waffe in Metern fest.

2. set_arm_power

void set_arm_power (int power);

Legt die Stärke (die Menge an Schaden) fest, die die ausgewählte Waffe zufügt.

3. shot

event shot (key victim, int power)

Dieses Ereignis wird aufgerufen, wenn wir ein Opfer angeschossen haben.

4. damage

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));
}


23. Ray Casting

  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)
  }

1. cast_ray

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");
}

24. Erdbeben

1. earthquake

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.

Anhang A : Bibliotheken

1. Konvertierungen

  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

2. Zeichenkettenbearbeitung

  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

3. Kalender

  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

4. Math

  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);

Anhang B : Erlaubnisse

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.

Anhang C : Einige Beispiele

Einen einfachen Türskript

  // 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});
  }

Ein Türskript mit dem Schließen der Tür nach 10 Sekunden

  // 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;
  }

Einen Lichtschalter

  // 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);
  }

Anhang D : Skript-Kosten

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.

Anhang E : Im Falle eines Fehlers

Im Falle eines Fehlers senden Sie eine Beschreibung an: [email protected]