Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Discussion: 1000m Menu-driven Intra-Sim Teleporter

Nepenthes Ixchel
Broadly Offended.
Join date: 6 Dec 2005
Posts: 696
07-15-2006 20:28
This teleporter was designed for use on an island with multiple scattered locations. It has a 1000m range, allowing any point below 768m to teleport to any other point also below 768m. A simple menu system allows the desination to be chosen before getting on the teleporter.

The main code block isn't commented, but the notes in the "Design" section should make it easy to figure out what is going on.

CODE


////////////////////////////////////////////////////////////////
// 1000m Menu-driven Intra-Sim Teleporter
// By Nepenthes Ixchel
// July 2006

/////////////////////////////////////////////////////////////////
// License:
// This code is released into the public domain, but if you sell
// it without making any changes to add value to it then hordes of
// purple undead monkeys will torment you in the afterlife.
//
// This code is released without any warranty of any sort.
//
// Code in this script includes:
//
// WarpPos by Keknehv Psaltery, April 2006, Public Domain
// This provides the instant movement code.
//
// Single Neat Elevator by Seagul Neville, Dec 2005, Public Domain
// This script started as SN_Elevator, but I don't think much
// of the original code survived. :-)

/////////////////////////////////////////////////////////////////
// Design:
//
// Menu system sets target location from pre-defined list
// When a user sits on the object it moves to the target location,
// unists the avatar, and returns. Use of WarpPos by Keknehv
// Psaltery makes this possible beyond the 10 metre limit normally
// associated with position changes.

/////////////////////////////////////////////////////////////////
// Quirks:
//
// If you move the teleporter after placing it you need to
// reset this script so it learns it's new home position
//
// All target locations must be under 768m in height
//
// All target locations must be in teh same sim as teh teleport
//
// Max distance is 1000m... but it's impossible to move more than
// 850m in a single sim without going higher than 768m.
//
// If use of llSetPrimitiveParams to bypass the 10m movement
// restriction is ever nerfed then this script will stop working.


/////////////////////////////////////////////////////////////////
// Usage
//
// Edit the list of locations.
// Place script in a prim
// Touch to get a menu to set destination
// Right click -> sit to teleport

/////////////////////////////////////////////////////////////////
//user variables, you should set these.

// A list of locations (names and position)
// This is for one sim only; teh sim the teleporter is in.
// No more than 12 locations or you'll get an error from llDialog
// Buttons are drawn left to right, bottom to top, in row of three.
list gLocations=[
"New Releases",<155,155,102>,
"Playful Kitten",<155,155,115>,
"Boneflower",<155,155,127>,
"IMD",<155,168,138>,
"Cyber Apoc",<164,52,27>,
"Pirate Kitty",<36,32,21>,
"Telehub",<155,108,106>,
"Shrine",<29,178,27>,
"Moon",<184,143,147>
];

// Text for the "pie menu"
string gSitText="Teleport";
// If you don't enable this teh teleport object will be left at the destination.
integer gReturnToStartPos=TRUE;
// Alpha for hovertext
float gTextAlpha=0.5;
// colour for hovertext
vector gTextColour=<1.0,1.0,1.0>;


/////////////////////////////////////////////////////////////////
//Runtime variables. You should leave these alone.

vector gStartPos=<0,0,0>;
key gAvatarID=NULL_KEY;
integer gChannel=574368374;
vector gTargetPos=<0,0,0>;


//////////////////////////////////////////////////////////////////
// Function for instant intra-sim movement

warpPos( vector d ) //R&D by Keknehv Psaltery, ~05/25/2006
{
if ( d.z > 768 ) //Otherwise we'll get stuck hitting the ceiling
d.z = 768;
//The number of jumps necessary
integer s = (integer)(llVecMag(d-llGetPos())/10)+1;
//Try and avoid stack/heap collisions
if ( s > 100 )
s = 100; // 1km should be plenty
//Solve '2^n=s'
integer e = (integer)( llLog( s ) / llLog( 2 ) );
list rules = [ PRIM_POSITION, d ]; //The start for the rules list
integer i;
for ( i = 0 ; i < e ; ++i ) //Start expanding the list
rules += rules;
integer r = s - (integer)llPow( 2, e );
if ( r > 0 ) //Finish it up
rules += llList2List( rules, 0, r * 2 + 1 );
llSetPrimitiveParams( rules );
}

//////////////////////////////////////////////////////////////////
// Main codeblock.

default
{
state_entry() {
llSetSitText(gSitText);
gStartPos = llGetPos();
llSitTarget(<0,0,1>,ZERO_ROTATION);
gChannel=(integer)llFrand(1000000000)+1000000000;
llSetText(llList2String(gLocations,0),gTextColour,gTextAlpha);
gTargetPos=(llList2Vector(gLocations,1));
llListen(gChannel,"",NULL_KEY,"");
}
on_rez(integer start_param){
llResetScript();
}
changed(integer change){
if(change & CHANGED_LINK)
{
gAvatarID = llAvatarOnSitTarget();
if(gAvatarID != NULL_KEY)
{
warpPos(gTargetPos);
llSleep(1);
llUnSit(gAvatarID);
llSleep(1);

if (gReturnToStartPos){
warpPos(gStartPos);
}
}
}
}

touch_start(integer number){
list options=[];
integer i =0;
for(i=0;i<llGetListLength(gLocations);i=i+2){
options+=[llList2String(gLocations,i)];
}
llDialog(llDetectedKey(0),"Choose target location",options,gChannel);
}

listen(integer channel, string name, key id, string message){
integer index=llListFindList(gLocations,[message]);
if (index==-1) return;
llSetText(llList2String(gLocations,index),gTextColour,gTextAlpha);
gTargetPos=llList2Vector(gLocations,index+1);
}

}
Nada Epoch
The Librarian
Join date: 4 Nov 2002
Posts: 1,423
Original Thread
07-19-2006 07:42
/15/0a/121162/1.html
_____________________
i've got nothing. ;)
Lizard Green
Reptillian
Join date: 28 Jun 2006
Posts: 20
07-19-2006 12:17
looks perfectly reasonable, but you might want to change the warPos function to the updated version.

also, since the destinations are hard coded, you could generate the lists on startup, and just pass them to llSetPrimitiveParams. though i don't think it would make much difference, warpPos seems fast enough as it is =)
Bo Twang
wants to know
Join date: 3 Apr 2006
Posts: 9
works great, thanks :)
07-19-2006 14:38
I just set up a ring of these and they worked great right out of the box. I did add authentication to restrict access to the group the object belongs to (in case this is helpful to others):


CODE
// user must belong to the same group as the tp
integer authenticate(key avie_key){
return llSameGroup(avie_key);
}

changed(integer change){
if(change & CHANGED_LINK)
{
gAvatarID = llAvatarOnSitTarget();
if(gAvatarID != NULL_KEY && authenticate(gAvatarID))
Harleen Gretzky
Registered User
Join date: 27 Oct 2005
Posts: 51
Reduced lag code
07-19-2006 17:43
By moving the listen to the touch_start event and getting its handle and then removing the listen at the end of the listen event, makes the listener only active when needed.


CODE


integer gDialogHandle;
default
.
.
.

//llListen(gChannel,"",NULL_KEY,"");
}
.
.
.

touch_start(integer number){
list options=[];
integer i =0;
for(i=0;i<llGetListLength(gLocations);i=i+2){
options+=[llList2String(gLocations,i)];
}
gDialogHandle = llListen(gChannel,"",NULL_KEY,"");
llDialog(llDetectedKey(0),"Choose target location",options,gChannel);
}

listen(integer channel, string name, key id, string message){
integer index=llListFindList(gLocations,[message]);
if (index==-1) return;
llSetText(llList2String(gLocations,index),gTextCol our,gTextAlpha);
gTargetPos=llList2Vector(gLocations,index+1);
llListenRemove(gDialogHandle);
}

}
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
07-20-2006 03:35
From: Bo Twang
I just set up a ring of these and they worked great right out of the box. I did add authentication to restrict access to the group the object belongs to (in case this is helpful to others):


CODE
// user must belong to the same group as the tp
integer authenticate(key avie_key){
return llSameGroup(avie_key);
}

changed(integer change){
if(change & CHANGED_LINK)
{
gAvatarID = llAvatarOnSitTarget();
if(gAvatarID != NULL_KEY && authenticate(gAvatarID))


Only problem with llSameGroup is that it will return true if the item isnt group owned and the toucher doesnt have a group tag active.

I use the following code to validate this

CODE
integer IsOwnerGroup(key id)
{
Owner = llGetOwner();
string name = llKey2Name(Owner);
// a group name will return an empty string
integer length = llStringLength(name);
integer ownergroup = 0;
if(length > 0)
{
ownergroup = (id == Owner );
}
else
{
ownergroup = llSameGroup(id);
}
return ownergroup;
}


Just my 2 pennies worth
Bitzer Balderdash
Dazed and Confused
Join date: 21 Dec 2005
Posts: 246
07-20-2006 03:38
Uhhh, that owner-group thing will only work in the case of deeded objects, not ones with a group merely set, where the owner is still reported as, well, the owner.

But most people who want to set group check features SHOULD know by now that you need to set the object to a group. And hey, it's easy enough to test :)
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
07-20-2006 04:05
From: Bitzer Balderdash
Uhhh, that owner-group thing will only work in the case of deeded objects, not ones with a group merely set, where the owner is still reported as, well, the owner.

But most people who want to set group check features SHOULD know by now that you need to set the object to a group. And hey, it's easy enough to test :)



Ahh,I'm still new enough to LSL get it wrong :(
Didnt realise the third permutation, i.e. just group set, was different.
Back to the drawing board.
Nepenthes Ixchel
Broadly Offended.
Join date: 6 Dec 2005
Posts: 696
07-20-2006 06:41
From: Harleen Gretzky
By moving the listen to the touch_start event and getting its handle and then removing the listen at the end of the listen event, makes the listener only active when needed.


Nice idea! That will eliminate a dozen listeners from the island.

It needs a test to see if the listener is already active though, otherwise you are left with a duplicate listener everytime someone touches and doesn't use the menu. I's say set gDialogHandle to -1 when there is no listener, and only start a new listener if gDialogHandle == -1.

The situation of a single listener being left active after an unused dialog box, until one actually is used, doesn't worry me much.

I'll leave coding this, implementing the new WarpPos, and implementing cross-sim transport with the even newer WarpPos as an exercise for the reader.
Burke Prefect
Cafe Owner, Superhero
Join date: 29 Oct 2004
Posts: 2,785
07-20-2006 08:03
Sweet. Would this be reasonably safe for mainland travel, as well, and can we assign waypoints? I haven't had a change to look all of the code over yet. :D
_____________________
Nepenthes Ixchel
Broadly Offended.
Join date: 6 Dec 2005
Posts: 696
07-20-2006 15:36
From: Burke Prefect
Sweet. Would this be reasonably safe for mainland travel, as well, and can we assign waypoints? I haven't had a change to look all of the code over yet. :D


I don't know what happens if WarpPos trys to move througha no-build or no-script area. Other than that, there is no reason I can see not to use this on the mainland.

There is no waypoint capability in the code, but it would be too hard to write it in; add the extra waypoints to the target list, alter the code to find the target name and step through each waypoint before returning.
Keknehv Psaltery
Hacker
Join date: 11 Apr 2005
Posts: 1,185
07-20-2006 15:51
WarpPos can go through land areas which are no-script or restricted access, but you'll have problems if it stops in one of those areas.

Burke, someone has made a cross-sim teleporter, located here .
Burke Prefect
Cafe Owner, Superhero
Join date: 29 Oct 2004
Posts: 2,785
07-20-2006 16:04
Doh. I mis-read 'intra' as 'inter'. >.<
_____________________
Dale Harmison
Registered User
Join date: 26 Dec 2005
Posts: 59
09-05-2006 19:20
hi guys im new to the whoe scripting thing and i was just wondering if itd be possible to set up more than 12 tp locations?
i know that some touch menues have that 'more option' on the end that takes you to a 2nd page which i dont know how to script into the main code.
could you please explain how thats done?
thank you!
Tiarnalalon Sismondi
Registered User
Join date: 1 Jun 2006
Posts: 402
09-06-2006 05:47
To do the more...you'd have to manually input it with a list with 11 buttons and a More.. button, and a 2nd list with the additional locations, etc till you had your limit.
I think in the way they have it done in this script it would look kinda like this...


CODE
list MENU_LOC1 = ["New Releases",<155,155,102>, 
"Playful Kitten",<155,155,115>,
"Boneflower",<155,155,127>,
"IMD",<155,168,138>,
"Cyber Apoc",<164,52,27>,
"Pirate Kitty",<36,32,21>,
"Telehub",<155,108,106>,
"Shrine",<29,178,27>,
"Moon",<184,143,147>, "More.."
];
list MENU_LOC2 = ["Really New Releases",<155,155,102>,
"Bashful Kitten",<155,155,115>,
"Marrowflower",<155,155,127>];

In the listen, you'd just have to have the listen check for the "More.." and pop up the menu for LOC2.

Also, on the listens...if you use llListenControl(), then you shouldn't have errant listens from multiple clicks....as long as you make sure to turn the listens off at the end of a menu option and only use the one channel, it will stop listening no matter how many times you clicked it prior to picking an option.
Dale Harmison
Registered User
Join date: 26 Dec 2005
Posts: 59
09-06-2006 09:31
since im not that expirienced at scripting that there didnt work ... :/
Tiarnalalon Sismondi
Registered User
Join date: 1 Jun 2006
Posts: 402
09-06-2006 11:09
Well the script currently is only set to use one list, you'd have to modify that part a little bit. Easiest to understand would be something concerning an integer check that points to which menu to use.

You could integrate this into the current code with some modifications.

CODE
integer menu;
default
{
state_entry()
{
menu = 1;
}
listen(integer channel, string name, key id, string message)
{
if (message == "More..")
menu = menu + 1;
}
}


I haven't really looked at the full code, but with some modifications, something like this should be workable.

I also have a bit of a cold, and am not able to get in SL to play around to test since I'm at work, or I would look at it fully to see what else it would take to set this up.

I've been using a more simplified version of something like this for little while now as a single target teleporter, but I will probably go ahead and set it up so I can use multiple destinations.
Prawnyloks Parker
"Prim Fiddler"
Join date: 6 Oct 2006
Posts: 420
02-14-2007 10:46
Just took a copy of the script 'cos it's exactly what I'm after. After pasting it into a new script and before even altering anything, I got a syntax error. 5 was very careful not to miss anything out. Help someone please, but bear in mind I am a complete novice.
Sterling Whitcroft
Registered User
Join date: 2 Jul 2006
Posts: 678
02-14-2007 18:05
Prawnyloks,
What error number did you get?
...or: Post your code back to this thread.

Also...one common problem with copying code from the forums is that the Forum Software sometimes inserts extra spaces. These need to be removed. If your error points to a specific line, look there.

An example of the 'spaces' error is show below:
Correct code:
integer length = llStringLength(name);
integer ownergroup = 0;

A typical spaces error might look like this:
integer length = llStringLe ngth(name);
integer ownergroup = 0;
Prawnyloks Parker
"Prim Fiddler"
Join date: 6 Oct 2006
Posts: 420
02-15-2007 14:04
From: Sterling Whitcroft
Prawnyloks,
What error number did you get?
...or: Post your code back to this thread.

Thanks Sterling. I got it sorted in the end, in-world. A good friend came by and helped me out. Turned out I had a comma in the wrong place. Can't remember what the error code was. Thanks for your help anyway :)
poopmaster Oh
The Best Person On Earth
Join date: 9 Mar 2007
Posts: 917
04-06-2007 08:51
I got it set up and working, just wondering is there a way to make it so as soon as they set destination in the dialog box and click ok it TP's the person right then and they do not have to go and click on the object again and choose teleport?
Nicolette Beebe
Registered User
Join date: 8 Feb 2007
Posts: 18
05-11-2007 11:20
From: poopmaster Oh
I got it set up and working, just wondering is there a way to make it so as soon as they set destination in the dialog box and click ok it TP's the person right then and they do not have to go and click on the object again and choose teleport?


There is no way I know of to force an AV to sit on the object with a llDialog, so, in my humble opinion the answer is: No

However, it would be possible to do that after you have already sat. But the sit is still required.
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
05-11-2007 13:14
As Nicolette stated make it sit based rather than touch based and then it is possible.
_____________________
I'm back......
Partington Gould
Registered User
Join date: 15 Sep 2005
Posts: 94
10-31-2007 21:38
Sorry to resurrect this old thread.

I use this for TP'ing to some skyboxes I rent, but have recently hit a problem with Ban Lines between the Skybox and the ground location, I could TP down to the ground, but the teleport prim was blocked from returning.

Is there a simple way to mod the destination to use waypoints, for both directions?

For me, I think I would need one straight up above each destination, so the prim would basically go up to 768m, along to above the destination, then straight down.

I'll keep hunting the other threads on long distance TP's, but will gladly accept any help :)


Thanks
PG
_____________________
PG - Permanently Confused and prone to Wandering
Tyken Hightower
Automagical
Join date: 15 Feb 2006
Posts: 472
10-31-2007 22:03
From: Partington Gould
Sorry to resurrect this old thread.

I use this for TP'ing to some skyboxes I rent, but have recently hit a problem with Ban Lines between the Skybox and the ground location, I could TP down to the ground, but the teleport prim was blocked from returning.

Is there a simple way to mod the destination to use waypoints, for both directions?

For me, I think I would need one straight up above each destination, so the prim would basically go up to 768m, along to above the destination, then straight down.

I'll keep hunting the other threads on long distance TP's, but will gladly accept any help :)


Thanks
PG

It sounds like you've pretty much got the idea. You need to only travel straight up or down once you're over the target.
_____________________
1 2