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 » Fri Jul 25, 2014 4:29 am

.. 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 » Fri Jul 25, 2014 5:56 pm

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: 270
Joined: Sat Dec 28, 2013 8:58 pm
Location: Between Lisbon - Portugal and London - UK
Has thanked: 260 times
Been thanked: 176 times
Contact:

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

Post by Carlos Loff » Fri Jul 25, 2014 6:34 pm

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
Join Kitely Group ---> Loff Virtual Worlds
Join Me on Facebook ---> https://www.facebook.com/groups/loffvirtualcities/
Join Google+ ---> OpenSim Virtual Worlds ---> https://plus.google.com/u/0/communities ... 2072972054
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 » Fri Jul 25, 2014 9:46 pm

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
Post Reply