Page 1 of 1

This could be a good train script, but..

Posted: Fri Jul 25, 2014 4:29 am
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();
      }
   }
}

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

Posted: Fri Jul 25, 2014 5:56 pm
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 ;-)

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

Posted: Fri Jul 25, 2014 6:34 pm
by Carlos Loff
Wonderful Sheera, bona try it for my futuristic Virtual London eco-trams, cheers

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

Posted: Fri Jul 25, 2014 9:46 pm
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!