This could be a good train script, but..

Creating scripts
Post Reply
User avatar
JCat Ziva
Posts: 11
Joined: Sat Jul 19, 2014 2:42 am
Has thanked: 7 times
Been thanked: 14 times

This could be a good train script, but..

Post by JCat Ziva »

.. I'm new at fully understanding scripts. I tried this one: http://forums.osgrid.org/viewtopic.php?f=5&t=4577 - and it's smooth, and close to what I was looking for, however it's meant for a critter, not a train (it glides up and down on its own). Someone else expanded on the script, setting it up like a tour, using waypoints -- meant for something like a train. Here's my dilemma: This is what I am looking for, however, I can't understand one part of the script. It apparently reads waypoints off a notecard, but the author doesn't give an example. I've used a few other scripts that call on notecards and I understand them, but this has got me confused. In addition, the script itself doesn't activate on touch, even though I saw a touch_start instruction in the code. Any coders around - that are above my super novice level that could help? ;) Thank you - here's the script):

Code: Select all

// Tour script by Rebekka Revnik
// it's free for everyone, no restrictions
// you may delete my name and claim it as your own script
// but if you give credit it would be nice :-)

// the first part is not mine, thanks and credits goes to Kayaker :-)

// Single Framed (SF) motion without llKeyframedMotion
// original script : Kayaker Magic
// from: http://forums.osgrid.org/viewtopic.php?f=5&t=4577
// minor changes by me

vector      SF_spos;        //start position
rotation    SF_srot;        //starting rotation
float       SF_stime;       //starting time
vector      SF_epos;        //ending position
rotation    SF_erot;        //ending rotation
float       SF_seconds;     //time to move that distance
integer     SF_target=-1;      //handle of last target position

SFrame()
{
   SF_spos=llGetPos();
   SF_srot=llGetRot();
   SF_stime=llGetTime();
   SF_epos = llList2Vector(Points, Count);
   SF_erot = llList2Rot(Rots, Count);
   SF_seconds=llVecDist(SF_epos, llGetPos()) / TIME;
   rotation t=<SF_srot.x-SF_erot.x,SF_srot.y-SF_erot.y,SF_srot.z-SF_erot.z,SF_srot.s-SF_erot.s>;
   if ((t.x*t.x + t.y*t.y + t.z*t.z + t.s*t.x)>0.5) SF_erot = <-SF_erot.x,-SF_erot.y,-SF_erot.z,-SF_erot.s>;
   llTargetRemove(SF_target);
   SF_target=llTarget(SF_epos, 0.1);
}

integer SFnotat()
{
   if (SF_target== -1) return TRUE;
   float time=llGetTime();
   time = (time-SF_stime)/SF_seconds;
   if (time>1.0)
   {
      llTargetRemove(SF_target);
      SF_target=-1;
      llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_POSITION,SF_epos,PRIM_ROTATION,SF_erot]);
      return TRUE;
   }
   float emit= 1.0-time;
   vector pos=SF_epos*time+SF_spos*emit;
   rotation rot = <
      SF_erot.x*time+SF_srot.x*emit,
      SF_erot.y*time+SF_srot.y*emit,
      SF_erot.z*time+SF_srot.z*emit,
      SF_erot.s*time+SF_srot.s*emit
         >;
   emit = llSqrt(rot.x*rot.x+rot.y*rot.y+rot.z*rot.z+rot.s*rot.s);
   rot = <rot.x/emit,rot.y/emit,rot.z/emit,rot.s/emit>;
   //vector v = llRot2Euler(rot);
   vector v = <0.0, 0.0, 1.0> * rot;
   //v.x = 0;
   //v.y = 0;
   //rot = llEuler2Rot(v);
   //llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_POSITION,pos,PRIM_ROTATION,llEuler2Rot(v)]);
   llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_POSITION,pos,PRIM_ROTATION,rot]);
   return FALSE;
}

// ab hier hab ich das geschrieben :-)

// Mach dir eine Notecard mit den folgenden Einträgen
// Gross/Kleinschreibung ist nicht wichtig, also DRIVE ist genauso gut wie drive oder Drive

// DRIVE = Position = Rotation      die Wegpunkte eben, mit Position und Rotation

// nach dem Wegpunkt (muss aber nicht sein)

// PAUSE = Sekunden               hält das Objekt ne Weile an
// TEXT = text                  sagt den Text im Chat

// now that's my part :-)

// Make a notecard with the folling entries
// it's not case sensitive, for example drive is accepted as DRIVE or Drive

// DRIVE = Position = Rotation      the waypoints with given params

// after the waypoint (optionally but but not required)

// PAUSE = seconds               makes the object to stay for a while
// TEXT = text                  says the text in chat

// wie es oben steht, die Schlüsselwörter
// as above, the keywords
string DRIVE = "drive";
string PAUSE = "pause";
string TEXT = "text";
// Name der Notecard
// name of the notecard
string NCNAME = "config";
// Trennzeichen für die Schlüsselwörter
// separator for keywords
string SEPARATOR = "=";
// wie schnell sich das Objekt bewegt
// 1 ist ungefähr 1 Meter pro Sekunde
// Grösser = schneller, aber auch mehr ruckeln
// how fast your object will move
// 1 means appr. 1 m per second
// a greater number ist faster but less smoothly
float TIME = 1.0;
// Stell es auf TRUE, dann kommen Infos im Chat über die Wegpunkte
// set it to TRUE to get informations about the waypoints in chat
integer DEBUG = FALSE;
// Wähle die Sprache, ich kann nur die beiden unten sprechen
// 0 = deutsch, 1 = englisch
// choose language, I speak only the two below
// 0 for german, 1 for english
integer LANGUAGE = 0;

list Points;
list Rots;
list Pause;
list Text;
integer NCLine;
key NCid;
integer Count;

// liest ein Zeile aus der Notecard und speichert sie
// reads a notecard line and saves it
Read(string data)
{
   list l = llParseString2List(data, [SEPARATOR], []);
   string s1 = llToLower(llStringTrim(llList2String(l, 0), STRING_TRIM));
   vector v1 = (vector)llToLower(llStringTrim(llList2String(l, 1), STRING_TRIM));
   rotation r1 = (rotation)llToLower(llStringTrim(llList2String(l, 2), STRING_TRIM));
   integer x;
   if(s1 == DRIVE)
   {
      if(v1 != ZERO_VECTOR)
      {
         Points += [v1];
         Rots += [r1];
         Pause += [0];
         Text += [""];
      }
   } else if(s1 == PAUSE)
   {
      x = llGetListLength(Pause) - 1;
      Pause = llListReplaceList(Pause, [(float)llToLower(llStringTrim(llList2String(l, 1), STRING_TRIM))], x, x);

   } else if(s1 == TEXT)
   {
      x = llSubStringIndex(data, SEPARATOR);
      data = llDeleteSubString(data, 0, x);
      x = llGetListLength(Text) - 1;
      Text = llListReplaceList(Text, [llStringTrim(data, STRING_TRIM)], x, x);
   }
}

// Sagt was in der Notecard steht (TEXT = text), ohne den Objektnamen
// es muss aber ein Leerzeichen drin sein und mindestens zwei Wörter haben
// sonst kommt nur der normale Chat mit dem Objektnamen
// says what you wrote in the notecard (TEXT = text) without the object name
// it has to be a space in it and at least two words
// otherwise you'll get only the normal chat with the object name
Say(string s)
{
   string s1 = llGetObjectName();
   integer x = llSubStringIndex(s, " ");
   if(x != -1)
   {
      string s2 = llGetSubString(s, 0, x - 1);
      s = llDeleteSubString(s, 0, x -1);
      s = "/me" + s;
      llSetObjectName(s2);
   }
   llSay(0, s);
   llSetObjectName(s1);
}

default
{
   state_entry()
   {
      llSetText("", <1,1,1>, 1.0);
      Points = [];
      Rots = [];
      Pause = [];
      Text = [];
      if(llGetInventoryType(NCNAME) == INVENTORY_NONE)
      {
         if(LANGUAGE == 0) llOwnerSay("Keine config-NC gefunden.");
         else if(LANGUAGE == 1) llOwnerSay("No config nc found.");

      } else
      {
         if(LANGUAGE == 0) llOwnerSay("Lese config, bitte warten...");
         else if(LANGUAGE == 1) llOwnerSay("Reading config nc, please wait...");
         NCLine = 0;
         NCid = llGetNotecardLine(NCNAME, NCLine++);
      }
   }
   dataserver(key requested, string data)
   {
      if(requested == NCid)
      {
         if(data != EOF)
         {
            Read(data);
            NCid = llGetNotecardLine(NCNAME, NCLine++);
         } else
         {
            if(LANGUAGE == 0) llOwnerSay("Fertig.");
            else if(LANGUAGE == 1) llOwnerSay("Ready.");
            if(llGetListLength(Points) == 0)
            {
               if(LANGUAGE == 0) llOwnerSay("Keine Wegpunkte gefunden.");
               else if(LANGUAGE == 1) llOwnerSay("No waypoints found.");
            }
            else
            {
               if(LANGUAGE == 0) llOwnerSay((string)llGetListLength(Points) + " Wegpunkte gelesen.");
               else if(LANGUAGE == 1) llOwnerSay((string)llGetListLength(Points) + " waypoints read.");
               state running;
            }
         }
      }
   }
}

state running
{
   state_entry()
   {
      if(LANGUAGE == 0) llSetText("Sitze und berühre mich", <1,1,1>, 1.0);
      else if(LANGUAGE == 1) llSetText("Sit down and touch me", <1,1,1>, 1.0);
   }
   touch_start(integer total_number)
   {
      state drive;
   }
}
state drive
{
   state_entry()
   {
      llSetText("", <1,1,1>, 1.0);
      Count = 0;
      // Ändere den Text hier drunter nach deinen Wünschen. Der kommt nur beim Start der Tour
      // Change the text below as you like. It appears only at the start of the tour
      Say("Willkommen bei der Tour auf meiner Insel. Sie dauert etwa 20 Minuten. Viel Spass :-)");
      SFrame();
   }
   not_at_target()
   {
      if(SFnotat())
      {
         if(DEBUG)
         {
            if(LANGUAGE == 0) llOwnerSay("Wegpunkt Nr. " + (string)(Count + 1) + " bei " + (string)llList2Vector(Points, Count));
            else if(LANGUAGE == 1) llOwnerSay("waypoint no. " + (string)(Count + 1) + " at " + (string)llList2Vector(Points, Count));
         }
         if(llList2String(Text, Count) != "") Say(llList2String(Text, Count));
         if(llList2Float(Pause, Count) > 0) llSleep(llList2Float(Pause, Count));
         Count++;
         if(Count == llGetListLength(Points)) state running;
         SFrame();
      }
   }
}
These users thanked the author JCat Ziva for the post (total 2):
Constance PeregrineCarlos Loff
Sheera Khan
Posts: 24
Joined: Sun Mar 03, 2013 4:44 pm
Has thanked: 2 times
Been thanked: 16 times

Re: This could be a good train script, but..

Post by Sheera Khan »

Huhu,

the format of the config notecard for the waypoints is described in the script ;-) it looks like this:

Code: Select all

DRIVE = <220.372055,19.999069,23.000000> = <0.000000,0.000000,0.000000,1.000000>
TEXT = First Stop
PAUSE = 5
DRIVE = <230.000931,30.372055,23.000000> = <0.000000,0.000000,0.707107,0.707107>
TEXT = Second Stop
PAUSE = 5
DRIVE = <219.627945,40.000931,23.000000> = <0.000000,0.000000,1.000000,0.000000>
TEXT = Third Stop
PAUSE = 5
DRIVE = <210.499069,29.627945,23.000000> = <0.000000,0.000000,-0.707107,0.707107>
TEXT = Forth Stop
PAUSE = 5
DRIVE, TEXT and PAUSE are keywords (case insensitive), = is the separator between parameters
DRIVE takes two parameters: position as a vector and rotation as a quaternion
TEXT takes the remainder of the line to be said in local chat by the object i.e. an explanation during a guided tour
PAUSE takes the number of seconds to remain at this place
The configuration card is required to be named config

To create the configuration card you can use another script by Rebekka Revnik:

Code: Select all

integer Channel = -888888;
integer Listener;
integer Listener1;

list Items;
integer Modus;

Menu()
{
    list l = ["Abbruch", "Ende", "Position", "Pause", "Text"];
    llListenRemove(Listener);
    Listener = llListen(Channel, "", llGetOwner(), "");
    llDialog(llGetOwner(), "Wähle eine Option:", l, Channel);
}

default
{
    state_entry()
    {
        Items = [];
        state running;
    }
}
state running
{
    state_entry()
    {
        Items = [];
    }
    touch_start(integer total_number)
    {
        if(llDetectedKey(0) == llGetOwner()) Menu();
    }
    listen(integer channel, string name, key id, string message)
    {
        if(channel == Channel)
        {
            if(message == "Abbruch")
            {
                Items = [];
                llListenRemove(Listener);
                return;
            } else if(message == "Ende")
            {
                osMakeNotecard("config", Items);
                llSay(0, "Die Notecard wurde erstellt.");
                llRemoveInventory(llGetScriptName());
            } else if(message == "Position")
            {
                string s = "DRIVE = " + (string)llGetPos() + " = " + (string)llGetRot();
                Items += [s];
                llSay(0, "Die Position/Rotation wurde gespeichert.");
                Menu();
                return;
            } else if(message == "Pause")
            {
                Modus = 1;
                llSay(0, "Bitte die Pause in Sekunden im Chat eingeben, z.B. 5.0.");
                Listener1 = llListen(0, "", llGetOwner(), "");
            } else if(message == "Text")
            {
                Modus = 2;
                llSay(0, "Bitte den gewünschten Text im Chat eingeben.");
                Listener1 = llListen(0, "", llGetOwner(), "");
            }
        } else if(channel == 0)
        {
            if(Modus == 1)
            {
                float f = (float)message;
                if(f > 0)
                {
                    Items += ["Pause = " + message];
                    llSay(0, "Pause gespeichert.");
                }
                llListenRemove(Listener1);
                Menu();
                return;
            } else if(Modus == 2)
            {
                message = llStringTrim(message, STRING_TRIM);
                if(message != "")
                {
                    Items += ["Text = " + message];
                    llSay(0, "Text gespeichert.");
                }
                llListenRemove(Listener1);
                Menu();
                return;
            }
        }
    }
}
Put this script into your train or whatever vehicle you use instead of the train script. Do not put a config card in this prim though. Move the object from one waypoint to the next along it's intended path. At each waypoint click on the object and a menu appears where you can store the position and rotation, a text message to be given in local chat at this point and a value for the pause. When you finished your path press the button "Ende" and the notecard is written (if Kitely permits this operation - I don't know) and the script deletes itself. Now you can put the trainscript into this object and it will take you along the path you defined if you sit on it ;-)

Have a lot of fun using this script

Ciaoooo

Sheera

PS.: If you would like to read the original thread for my information, it is located here: http://www.gridtalk.de/showthread.php?tid=977, it's in german though ;-)
These users thanked the author Sheera Khan for the post (total 3):
Constance PeregrineMarstol NitelySelby Evans
User avatar
Carlos Loff
Posts: 280
Joined: Sat Dec 28, 2013 8:58 pm
Location: Lisbon - Portugal
Has thanked: 263 times
Been thanked: 191 times
Contact:

Re: This could be a good train script, but..

Post by Carlos Loff »

Wonderful Sheera, bona try it for my futuristic Virtual London eco-trams, cheers
These users thanked the author Carlos Loff for the post:
Constance Peregrine
Kitely - Meta Lisbon --> grid.kitely.com:8002:Meta Lisbon Startups
Join Me on Meetup --> https://www.meetup.com/metalisbonstartups/
Join Kitely Group --> Meta Lisbon Startups
User avatar
JCat Ziva
Posts: 11
Joined: Sat Jul 19, 2014 2:42 am
Has thanked: 7 times
Been thanked: 14 times

Re: This could be a good train script, but..

Post by JCat Ziva »

Sheera!! More like Savior! :D

Can't thank you enough for that help. See, I'm still fairly new. I read the instructions in the comments, but wanted to see a sample of the formula laid out, because I had another program which was similar, but it looked for quotation marks (and didn't have a rotation #). This works wonderful and smooth! And the extra waypoint reader script you included is a major bonus - love it! Thank you Rebekka Revnik where ever you are! Now I can move on with my life!


Thanks, again.

@Carlos Loff - I will visit your region over the weekend; sounds interesting!
These users thanked the author JCat Ziva for the post (total 3):
Constance PeregrineCarlos LoffMarstol Nitely
User avatar
Kayaker Magic
Posts: 354
Joined: Sun Dec 01, 2013 8:40 am
Has thanked: 52 times
Been thanked: 393 times

Re: This could be a good train script, but..

Post by Kayaker Magic »

This old TRAIN/TOUR script worked on Kitely under OpenSim 0.8.2 but it doesn’t work on Kitely any more or anyplace else on the 0.9.* Metaverse. I checked into it and there is apparently a slight difference in the tolerance of llTarget. If you go into that script and change the second argument to llTarget from 0.1 to 0.001, then the script will work in 0.9.1.1 in Kitely and other places running up-to-date versions.

HOWEVER, Rebekka wrote that script using some code I published back when the latest version of OpenSim was 0.7.0 and some of the LSL functions had not been written yet. That code of mine was intended to do the job that is now done more efficiently by the llSetKeyframedMotion function built into all versions of OpenSim since 0.7.1! So I took Rebekka’s code, re-wrote it to use llSetKeyframedMotion, and removed all my obsolete code. The resulting script can be dropped into an existing tour prim and will still read the notecards created by Rebekka’s CONFIG CARD CREATOR script. Below is my new TRAIN/TOUR script version, and also Rebekka’s creator script and instructions for those of you who don’t have those yet. So go to the bottom of this post for the instructions....

New TOUR/TRAIN script:

Code: Select all

// Tour script by Rebekka Revnik, updated 2020-02-16 by Kayaker Magic
// it's free for everyone, no restrictions
// you may delete our names and claim it as your own script
// but if you give credit it would be nice :-)

// Kayaker:
//  Rebekka based this on some functions I wrote in LSL to
//  impliment llSetKeyframedMotion back before OpenSim 0.7.1 when
//  llSetKeyframedMotion was finally added to OpenSim.
//  So all that code is not necessary any more!
//  I re-wrote this to use the new function, and made many other changes...
//      I got rid of the lists, just executed the notecard lines as I read them
//      calculated the time to produce the desired velocity
//      added a command to change the velocity


// ab hier hab ich das geschrieben :-)

// Mach dir eine Notecard mit den folgenden Einträgen
// Gross/Kleinschreibung ist nicht wichtig, also DRIVE ist genauso gut wie drive oder Drive

// DRIVE = Position = Rotation      die Wegpunkte eben, mit Position und Rotation

// nach dem Wegpunkt (muss aber nicht sein)

// PAUSE = Sekunden               hält das Objekt ne Weile an
// TEXT = text                  sagt den Text im Chat
//
// now that's my part :-)

// Make a notecard with the folling entries
// it's not case sensitive, for example drive is accepted as DRIVE or Drive

// DRIVE = Position = Rotation      the waypoints with given params

// after the waypoint (optionally but but not required)

// PAUSE = seconds               makes the object to stay for a while
// TEXT = text                  says the text in chat
// VEL = speed    	(in meters/second, defaults to 3.0)

// wie es oben steht, die Schlüsselwörter
// as above, the keywords
string DRIVE = "drive";
string PAUSE = "pause";
string TEXT = "text";
string VEL = "vel";         //change the velocity
// Name der Notecard
// name of the notecard
string NCNAME = "config";
// Trennzeichen für die Schlüsselwörter
// separator for keywords
string SEPARATOR = "=";
// Wähle die Sprache, ich kann nur die beiden unten sprechen
// 0 = deutsch, 1 = englisch
// choose language, I speak only the two below
// 0 for german, 1 for english
integer LANGUAGE = 1;
float velocity=3.0;     //how fast to move, meters/second

integer NCLine; //what line to read from notecard next
key NCid;       //handle for dataserver


// liest ein Zeile aus der Notecard und speichert sie
// reads a notecard line and executes it
Read(string data)
{
   list l = llParseString2List(data, [SEPARATOR], []);
   string cmd = llToLower(llStringTrim(llList2String(l, 0), STRING_TRIM));
   if(cmd == DRIVE)
   {
        llSetKeyframedMotion([],[KFM_COMMAND,KFM_CMD_STOP]);    //stop any older one
        vector pos = (vector)llStringTrim(llList2String(l, 1), STRING_TRIM);
        rotation rot = (rotation)llStringTrim(llList2String(l, 2), STRING_TRIM);
        float dist=llVecDist(pos,llGetPos());
        float secs = dist/velocity;     //calculate the time to get there
        llSetKeyframedMotion([pos-llGetPos(),rot/llGetRot(),secs],[]);
        secs = secs-0.1;            //set the timer a little early for llGetNotecardLine
        if (secs<0.0) secs=0.0;
        llSetTimerEvent(secs);
    }
    else if(cmd == PAUSE)
    {
        llSetTimerEvent((float)llStringTrim(llList2String(l, 1), STRING_TRIM));
    }
    else if(cmd == TEXT)
    {
        integer x = llSubStringIndex(data, SEPARATOR);
        data = llStringTrim(llDeleteSubString(data, 0, x), STRING_TRIM);
        Say(data);
        NCid = llGetNotecardLine(NCNAME, NCLine++);
    }
    else   //don't understand this line
        NCid = llGetNotecardLine(NCNAME, NCLine++);
}

// Sagt was in der Notecard steht (TEXT = text), ohne den Objektnamen
// es muss aber ein Leerzeichen drin sein und mindestens zwei Wörter haben
// sonst kommt nur der normale Chat mit dem Objektnamen
// says what you wrote in the notecard (TEXT = text) without the object name
// it has to be a space in it and at least two words
// otherwise you'll get only the normal chat with the object name
Say(string s)
{
   string s1 = llGetObjectName();
   integer x = llSubStringIndex(s, " ");
   if(x != -1)
   {
      string s2 = llGetSubString(s, 0, x - 1);
      s = llDeleteSubString(s, 0, x -1);
      s = "/me" + s;
      llSetObjectName(s2);
   }
   llSay(0, s);
   llSetObjectName(s1);
}

default
{
    state_entry()
    {
        llSetKeyframedMotion([],[KFM_COMMAND,KFM_CMD_STOP]);    //stop any older one
        llSetText("", <1,1,1>, 1.0);
      if(llGetInventoryType(NCNAME) == INVENTORY_NONE)
      {
         if(LANGUAGE == 0) llOwnerSay("Keine config-NC gefunden.");
         else if(LANGUAGE == 1) llOwnerSay("No config nc found.");

      } else
      {
         llSetText("Sit and touch to start",<0,1,0>,1.0);
      }
   }
   touch_start(integer total_number)    //starts the tour over again
   {
        llSetKeyframedMotion([],[KFM_COMMAND,KFM_CMD_STOP]);    //stop any older one
        NCLine=0;
        NCid = llGetNotecardLine(NCNAME, NCLine++);
        llSetText("",<0,1,0>,1.0);
   } //touch_start
    dataserver(key requested, string data)
    {
        if (data == EOF)
        {
            llSetText("Sit and touch to start",<0,1,0>,1.0);
            return;
        }
        Read(data);
    } //dataserver
    
    timer()
    {
        llSetTimerEvent(0.0);   //wait for next command for time
        NCid = llGetNotecardLine(NCNAME, NCLine++);
    } //timer
}
Original CONFIGURATION CARD CREATOR FOR TOUR / TRAIN SCRIPT

Code: Select all

integer Channel = -888888;
integer Listener;
integer Listener1;

list Items;
integer Modus;

Menu()
{
    list l = ["CANCEL", "END", "Position", "Pause", "Text"];
    llListenRemove(Listener);
    Listener = llListen(Channel, "", llGetOwner(), "");
    llDialog(llGetOwner(), "Wähle eine Option:", l, Channel);
}

default
{
    state_entry()
    {
        Items = [];
        state running;
    }
}
state running
{
    state_entry()
    {
        Items = [];
    }
    touch_start(integer total_number)
    {
        if(llDetectedKey(0) == llGetOwner()) Menu();
    }
    listen(integer channel, string name, key id, string message)
    {
        if(channel == Channel)
        {
            if(message == "CANCEL")
            {
                Items = [];
                llListenRemove(Listener);
                return;
            } else if(message == "END")
            {
                osMakeNotecard("config", Items);
                llSay(0, "Die Notecard wurde erstellt.");
                llRemoveInventory(llGetScriptName());
            } else if(message == "Position")
            {
                string s = "DRIVE = " + (string)llGetPos() + " = " + (string)llGetRot();
                Items += [s];
                llSay(0, "Die Position/Rotation wurde gespeichert.");
                Menu();
                return;
            } else if(message == "Pause")
            {
                Modus = 1;
                llSay(0, "Bitte die Pause in Sekunden im Chat eingeben, z.B. 5.0.");
                Listener1 = llListen(0, "", llGetOwner(), "");
            } else if(message == "Text")
            {
                Modus = 2;
                llSay(0, "Bitte den gewünschten Text im Chat eingeben.");
                Listener1 = llListen(0, "", llGetOwner(), "");
            }
        } else if(channel == 0)
        {
            if(Modus == 1)
            {
                float f = (float)message;
                if(f > 0)
                {
                    Items += ["Pause = " + message];
                    llSay(0, "Pause gespeichert.");
                }
                llListenRemove(Listener1);
                Menu();
                return;
            } else if(Modus == 2)
            {
                message = llStringTrim(message, STRING_TRIM);
                if(message != "")
                {
                    Items += ["Text = " + message];
                    llSay(0, "Text gespeichert.");
                }
                llListenRemove(Listener1);
                Menu();
                return;
            }
        }
    }
}
Original instructions from Rebekka:
DRIVE, TEXT and PAUSE are keywords (case insensitive), = is the separator between parameters
DRIVE takes two parameters: position as a vector and rotation as a quaternion
TEXT takes the remainder of the line to be said in local chat by the object i.e. an explanation during a guided tour
PAUSE takes the number of seconds to remain at this place
The configuration card is required to be named config


Put CONFIGURATION CREATOR script into your train or whatever vehicle you use.

Do not put a config card in this prim though.

Move the object from one waypoint to the next along it's intended path.

At each waypoint click on the object and a menu appears where you can store the position and rotation, a text message to be given in local chat at this point and a value for the pause.

When you finished your path press the button "Ende" and the notecard is written

The script deletes itself.

Now you can put the TOUR / TRAIN script into this object and it will take you along the path you defined if you sit on it ;-)
These users thanked the author Kayaker Magic for the post (total 5):
Selby EvansZyzzyx QinanIlan TochnerGraham MillsTrouble Ahead
User avatar
John Mela
Posts: 91
Joined: Tue Feb 04, 2014 9:50 pm
Has thanked: 139 times
Been thanked: 127 times
Contact:

Re: This could be a good train script, but..

Post by John Mela »

Those are interesting scripts.

I notice that the dataserver event in the first script doesn't check the "requested" ID against the id returned by the notecard functions. This presumably means that it would be possible to control the object by sending messages to it from another object, using osMessageObject. Whether that's a bug or a feature depends on your outlook!
These users thanked the author John Mela for the post:
Ilan Tochner
User avatar
Zyzzyx Qinan
Posts: 17
Joined: Tue Jan 29, 2019 1:37 am
Has thanked: 49 times
Been thanked: 17 times

Re: This could be a good train script, but..

Post by Zyzzyx Qinan »

Kayaker Magic

I was using the Tour/Train script with 43 waypoints successfully before the upgrade to OpenSim 0.9.1.1
I tried your new re-write of the script AND I also tried the old script by changing the second argument to llTarget from 0.1 to 0.001,
In both cases the scripts work BUT they both stop at totally random waypoints then it waits there about 30 minutes then skips the rest of the waypoints and heads for the 1st waypoint and starts over by itself, then stops again at another random waypoint. (We are using OBE physics before and after upgrade. We tried ubOBE but it broke some of our Mesh buildings)

Any thoughts why this might be happening?
Post Reply