Jump to content
Erwin Solo

Experience Teleporter using landmarks

Recommended Posts

Below is my version of an experience based teleporter.  It works upon avatar collision with the teleporter.  Instead of requiring manual entry of coordinates, it reads the necessary coordinates from a landmark in inventory.  Any improvements would be most welcome.

 

Experience Based Teleporter using Landmarks

// Erwin Solo 2018-03-11 
// Experience Based Teleporter

// Step 1. Set up an experience on your land.  See Linden Article at
// https://community.secondlife.com/knowledgebase/english/experiences-in-second-life-r1365/
// Recompile this script to set it to the experience name of your land.  Quoting the Linden Article:

// "LSL scripts must be specifically compiled for an experience in order to make use of experience-related LSL functions.  The bottom of the LSL editor in the Second Life Viewer includes a checkbox for Use Experience and a dropdown for selecting which of your experience keys you wish the script to use."

// Step 3: Place one landmark in the teleporter and you are done

// ===== Don't change anything below here ===========

vector gvSIM_Global_Coordinates = ZERO_VECTOR;
vector gvLocal_Coordinates = ZERO_VECTOR;
vector gvTargetSimCorner = ZERO_VECTOR;
vector gvRelative_Coordinates = ZERO_VECTOR;
vector gvCurrentSimGlobal = ZERO_VECTOR;
key gLocalCoordinateQuery = NULL_KEY;
string gLandMarkName = "";

default
{
    state_entry()
    {
        llVolumeDetect(TRUE);
        
        // Get Global Coordinates of Current SIM
        gvCurrentSimGlobal =llGetRegionCorner();
        llSay (0, (string) gvCurrentSimGlobal);
                
        //complain if there are no landmarks
        if (llGetInventoryNumber(INVENTORY_LANDMARK) == 0)
        {
            llSay(PUBLIC_CHANNEL, "There are no landmarks in me.  You need to put a landmark in me for me to work.");
        }
         //complain if there is more than one landmark
        else if (llGetInventoryNumber(INVENTORY_LANDMARK) > 1)
        {
            llSay(PUBLIC_CHANNEL, "There are TOO MANY landmarks in me.  You need to put EXACTLY ONE landmark in me for me to work.");
        }
        
        else
        {
            // Get name of the single landamrk in inventory
            gLandMarkName = llGetInventoryName(INVENTORY_LANDMARK, 0);
            // Dataserver call for local coordinates of landmark
            gLocalCoordinateQuery = llRequestInventoryData( gLandMarkName );
        }

    }
    
    on_rez(integer start_param) 
    { 
        llResetScript();  
    }
    
    changed( integer change )
    {
        if(change & (CHANGED_OWNER | CHANGED_REGION | CHANGED_INVENTORY))
        {
            llResetScript(); 
        }
    }
    
    dataserver(key query_id, string data)
    {

        if (query_id == gLocalCoordinateQuery)
        {
            gvRelative_Coordinates = (vector)data;
            gvSIM_Global_Coordinates = gvRelative_Coordinates + gvCurrentSimGlobal;
            
            // Perform a bit of vector math and rounding
            gvTargetSimCorner = 
            <
            256.0 * (float) ((integer) (gvSIM_Global_Coordinates.x / 256.0)), 
            256.0 * (float) ((integer) (gvSIM_Global_Coordinates.y / 256.0)), 
            0.0 
            >;
            gvLocal_Coordinates = gvSIM_Global_Coordinates - gvTargetSimCorner; 
//            llOwnerSay ("gvSIM_Global_Coordinates:" + (string) gvSIM_Global_Coordinates);
//            llOwnerSay ("gvTargetSimCorner:" + (string)gvTargetSimCorner);
//            llOwnerSay ("gvLocal_Coordinates:" + (string)gvLocal_Coordinates);
        }
    }
    
    collision_start(integer detected)
    {
        llRequestExperiencePermissions(llDetectedKey(0), "");
        llSay(0, "You need to accept the Experience Permission Request for this to work.");
    }
    
    experience_permissions( key agent_id )
    {
        llTeleportAgentGlobalCoords(agent_id, gvTargetSimCorner, gvLocal_Coordinates, ZERO_VECTOR);
    }
    
    experience_permissions_denied( key agent_id, integer reason )
    {
        llSay(0, "Denied: " + llGetExperienceErrorMessage(reason) + ".  You need to accept the Experience Permission Request for this to work.");
    }
}

 

  • Like 3

Share this post


Link to post
Share on other sites
Posted (edited)

This is a nice script. The only thing I might suggest is to clarify the error messaging:

experience_permissions_denied( key agent_id, integer reason )
{
    llSay(0, "Denied: " + llGetExperienceErrorMessage(reason));
	if (reason == 14)
	{
		llRegionSayTo(agent_id,0, "You need to accept the Experience Permission Request for this to work.");
	}
}

and then remove the message from the collision_start event, since it's only necessary to say it once, and only if the TP fails.

Edited by Rolig Loon
  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

As Rolig says, it's a nice script.   However, it seems to me to overcomplicate things a bit.

Since it's got a landmark in it, you don't need to go to all that trouble to read the world coordinate to which the landmark points.   Instead of using  llTeleportAvatarGlobalCoords  you could achieve the same result simply by using

llTeleportAgent( gLandMarkName,<0.0,0.0,0.0>, <0.0,,0.0,0.0>);

You need llTeleportAvatarGlobalCoords for those times when you don't have/can't use a landmark, and you have to read the region's global coordinates from llGetRegionName.   But if you can use a landmark, then it's so much easier than doing all those calculations.

Share this post


Link to post
Share on other sites
30 minutes ago, Innula Zenovka said:

As Rolig says, it's a nice script.   However, it seems to me to overcomplicate things a bit.

Since it's got a landmark in it, you don't need to go to all that trouble to read the world coordinate to which the landmark points.   Instead of using  llTeleportAvatarGlobalCoords  you could achieve the same result simply by using

llTeleportAgent( gLandMarkName,<0.0,0.0,0.0>, <0.0,,0.0,0.0>);

You need llTeleportAvatarGlobalCoords for those times when you don't have/can't use a landmark, and you have to read the region's global coordinates from llGetRegionName.   But if you can use a landmark, then it's so much easier than doing all those calculations.

 

I completely agree.  I scripted two versions.  I first scripted a version using llTeleportAgent( key avatar, string landmark, vector position, vector look_at ) , but it was failing about 50% of the time.  I couldn't figure out was was wrong, and so I used my other version based on llTeleportAgentGlobalCoords( key agent, vector global_coordinates, vector region_coordinates, vector look_at ). 

2 hours ago, Rolig Loon said:

This is a nice script. The only thing I might suggest is to clarify the error messaging:


experience_permissions_denied( key agent_id, integer reason )
{
    llSay(0, "Denied: " + llGetExperienceErrorMessage(reason));
	if (reason == 14)
	{
		llRegionSayTo(agent_id,0, "You need to accept the Experience Permission Request for this to work.");
	}
}

and then remove the message from the collision_start event, since it's only necessary to say it once, and only if the TP fails.

 

Thanks.  This is what I ended up with.

// Erwin Solo 2018-03-11 
// Experience Based Teleporter

// Step 1. Set up an experience on your land.  See Linden Article at
// https://community.secondlife.com/knowledgebase/english/experiences-in-second-life-r1365/
// Recompile this script to set it to the experience name of your land.  Quoting the Linden Article:

// "LSL scripts must be specifically compiled for an experience in order to make use of experience-related LSL functions.  The bottom of the LSL editor in the Second Life Viewer includes a checkbox for Use Experience and a dropdown for selecting which of your experience keys you wish the script to use."

// Step 3: Place one landmark in the teleporter and you are done

integer giDebug = FALSE; // set to FALSE to quiet local debug messages or to TRUE to display local debug messages

// ===== Don't change anything below here ===========

vector gvSIM_Global_Coordinates = ZERO_VECTOR;  // Global coordinates of your landmark, once finally calculated
vector gvLocal_Coordinates = ZERO_VECTOR; // Local coordinates of your landmark on its destination region
vector gvTargetSimCorner = ZERO_VECTOR; // Global coordinates for the Region-Corner of your landmark, once finally calculated
vector gvRelative_Coordinates = ZERO_VECTOR; // Relative coordinates of your landmark relative to the position of your teleporter
vector gvCurrentSimGlobal = ZERO_VECTOR; // Global coordinates for the Region-Corner of the region on which your teleporter resides
key gkLocalCoordinateQuery = NULL_KEY; // a handle to be used in a dataserver call
string gsLandMarkName = ""; // The name of the landmark in your inventory
string gsErrorMessage = ""; // Used to build string for error messages

default
{
    state_entry()
    {
        // Prepare object to collision_start events when interpenetrating. 
        llVolumeDetect(TRUE);
        
        // Get Global Coordinates of corner of Current SIM on which the teleporter resides
        gvCurrentSimGlobal =llGetRegionCorner();
                
        //complain if there are no landmarks
        if (llGetInventoryNumber(INVENTORY_LANDMARK) == 0)
        {
            llSay(PUBLIC_CHANNEL, "There are no landmarks in me.  You need to put a landmark in me for me to work.");
        }
         //complain if there is more than one landmark
        else if (llGetInventoryNumber(INVENTORY_LANDMARK) > 1)
        {
            llSay(PUBLIC_CHANNEL, "There are TOO MANY landmarks in me.  You need to put EXACTLY ONE landmark in me for me to work.");
        }
        
        else
        {
            // Get name of the single landamrk in inventory
            gsLandMarkName = llGetInventoryName(INVENTORY_LANDMARK, 0);
            // Dataserver call for local coordinates of landmark
            gkLocalCoordinateQuery = llRequestInventoryData( gsLandMarkName );
        }

    }
    
    on_rez(integer start_param) 
    { 
        llResetScript();  
    }
    
    changed( integer change )
    {
        if(change & (CHANGED_OWNER | CHANGED_REGION | CHANGED_INVENTORY))
        {
            llResetScript(); 
        }
    }
    
    dataserver(key query_id, string data)
    {

        if (query_id == gkLocalCoordinateQuery)
        {
            gvRelative_Coordinates = (vector)data;
            gvSIM_Global_Coordinates = gvRelative_Coordinates + gvCurrentSimGlobal;
            
            // Perform a bit of vector math and rounding.
            // Math programers may feel the urge to add a small value before rounding, 
            // to prevent erronious down-rounding but that is not necessary 
            // unless the landmark is exactly at the Region's <0.0, 0.0, 0.0> point
            // and that is an impossible landmark to create inworld because avatars
            // all have non-zero height.
            gvTargetSimCorner = 
            <
            256.0 * (float) ((integer) (gvSIM_Global_Coordinates.x / 256.0)), 
            256.0 * (float) ((integer) (gvSIM_Global_Coordinates.y / 256.0)), 
            0.0 
            >;
            gvLocal_Coordinates = gvSIM_Global_Coordinates - gvTargetSimCorner; 
            if (giDebug)
            {  
                llSay (PUBLIC_CHANNEL, "gvCurrentSimGlobal:" + (string)gvCurrentSimGlobal);
                llSay (PUBLIC_CHANNEL, "gvSIM_Global_Coordinates:" + (string) gvSIM_Global_Coordinates);
                llSay (PUBLIC_CHANNEL, "gvTargetSimCorner:" + (string)gvTargetSimCorner);
                llSay (PUBLIC_CHANNEL, "gvLocal_Coordinates:" + (string)gvLocal_Coordinates);
            }
        }
    }
    
    collision_start(integer detected)
    {
        llRequestExperiencePermissions(llDetectedKey(0), "");
    }
    
    experience_permissions( key agent_id )
    {
        llTeleportAgentGlobalCoords(agent_id, gvTargetSimCorner, gvLocal_Coordinates, ZERO_VECTOR);
    }
    
    experience_permissions_denied( key agent_id, integer reason )
    {
        gsErrorMessage = "Teleport Denied: " + llGetExperienceErrorMessage(reason) + ". ";
        if (reason == 1) gsErrorMessage += "The call failed due to too many recent calls."; 
        else if (reason == 2) gsErrorMessage += "The region currently has experiences disabled."; 
        else if (reason == 3) gsErrorMessage += "One of the string arguments was too big to fit in the key-value store."; 
        else if (reason == 4) gsErrorMessage += "Experience permissions were denied by the user."; 
        else if (reason == 5) gsErrorMessage += "This script is not associated with an experience."; 
        else if (reason == 6) gsErrorMessage += "The sim was unable to verify the validity of the experience. Retrying after a short wait is advised."; 
        else if (reason == 7) gsErrorMessage += "The script is associated with an experience that no longer exists."; 
        else if (reason == 8) gsErrorMessage += "The experience owner has temporarily disabled the experience."; 
        else if (reason == 9) gsErrorMessage += "The experience has been suspended by Linden Lab customer support."; 
        else if (reason == 10) gsErrorMessage += "An unknown error not covered by any of the other predetermined error states."; 
        else if (reason == 11) gsErrorMessage += "An attempt to write data to the key-value store failed due to the data quota being met."; 
        else if (reason == 12) gsErrorMessage += "The key-value store is currently disabled on this region."; 
        else if (reason == 13) gsErrorMessage += "Unable to communicate with the key-value store."; 
        else if (reason == 14) gsErrorMessage += "The requested key does not exist."; 
        else if (reason == 15) gsErrorMessage += "A checked update failed due to an out of date request."; 
        else if (reason == 16) gsErrorMessage += "The content rating of the experience exceeds that of the region."; 
        else if (reason == 17) gsErrorMessage += "The experience is blocked or not enabled for this land."; 
        else if (reason == 18) gsErrorMessage += "The request for experience permissions was ignored."; 

        llSay(PUBLIC_CHANNEL, gsErrorMessage);
        llRegionSayTo( agent_id, PUBLIC_CHANNEL, gsErrorMessage );  
    }
}

 

  • Like 1

Share this post


Link to post
Share on other sites

Hmmm.. You didn't actually have to go to that trouble. If you ask for llGetExperienceErrorMessage(reason), that's exactly the text you get anyway.

Share this post


Link to post
Share on other sites
Posted (edited)

I used

string gsErrorMessage = "Teleport Denied: " + llGetExperienceErrorMessage(reason) + ". ";

to get and format the llGetExperienceErrorMessage(reason), and then I used += to add the longer explanation.  In particular, I think these are useful to end-users:

else if (reason == 4) gsErrorMessage += "Experience permissions were denied by the user."; 

else if (reason == 8) gsErrorMessage += "The experience owner has temporarily disabled the experience.";

else if (reason == 18) gsErrorMessage += "The request for experience permissions was ignored."; 

 

Some of the others will be useful to me or other owners/installers. 

Edited by Erwin Solo
  • Like 1

Share this post


Link to post
Share on other sites

Rather then truncate the position to the meter I actually add +/- 0.5M in a random direction on X and Y - I find if you have 2 or 3 people walk through in quick succession it stops them all piling up on each other.

  • Like 1

Share this post


Link to post
Share on other sites
Posted (edited)

Well, if I thought there would be this many changes I would have posted in LSL Scripting instead of LSL Library.  Apologies.  Next time I'll start off in LSL scripting.

20 hours ago, Callum Meriman said:

Rather then truncate the position to the meter I actually add +/- 0.5M in a random direction on X and Y - I find if you have 2 or 3 people walk through in quick succession it stops them all piling up on each other.

The random dither on the landing point is a good idea.  I have added that.  The rounding actually only applies to the SIM/Region corner calculation.  Logically, or philosophically, the SIM/Region corner is an integer, though the vectors carry it in float values.

 

// Erwin Solo 2018-03-12b V1.0.2
// Experience Based Teleporter

// Step 1. Set up an experience on your land.  See Linden Article at
// https://community.secondlife.com/knowledgebase/english/experiences-in-second-life-r1365/
// Recompile this script to set it to the experience name of your land.  Quoting the Linden Article:

// "LSL scripts must be specifically compiled for an experience in order to make use of experience-related LSL functions.  The bottom of the LSL editor in the Second Life Viewer includes a checkbox for Use Experience and a dropdown for selecting which of your experience keys you wish the script to use."

// Step 3: Place one landmark in the teleporter and you are done

// Revisions

// 2018-03-12  Revision 1.0.2 Introduced random dither to landing location to keep avatars from landing on top of one another

// 2018-03-12  Revision 1.0.1 

// Added ability to control the direction in which avatar faces when landing: North, South, East, West, North East, North West, South East, South West.

// Disabled teleportation until device initialization is complete.

// 2018-03-11  Revision 1.0 Initial Release

integer giDebug = FALSE; // set to FALSE to quiet local debug messages or to TRUE to display local debug messages

// Vector to lookat-direction when landing after teleportation
// North is  <0., 1., 0.> 
// South is <0., -1., 0.>
// East is <1.,0.,0.>
// West is <-1.,0.,0.>
// North West is <-1.,1.,0.>
// North East is <1.,1.,0.>
// South West is <-1.,-1.,0.>
// South East is <1.,-1.,0.>

vector gvLookat = <0.,1.,0.>; // Populate with Vector to lookat-direction when landing after teleportation

// ===== Don't change anything below here ===========

vector gvSIM_Global_Coordinates = ZERO_VECTOR;  // Global coordinates of your landmark, once finally calculated
vector gvLocal_Coordinates = ZERO_VECTOR; // Local coordinates of your landmark on its destination region
vector gvTargetSimCorner = ZERO_VECTOR; // Global coordinates for the Region-Corner of your landmark, once finally calculated
vector gvRelative_Coordinates = ZERO_VECTOR; // Relative coordinates of your landmark relative to the position of your teleporter
vector gvCurrentSimGlobal = ZERO_VECTOR; // Global coordinates for the Region-Corner of the region on which your teleporter resides
key gkLocalCoordinateQuery = NULL_KEY; // a handle to be used in a dataserver call
string gsLandMarkName = ""; // The name of the landmark in your inventory
string gsErrorMessage = ""; // Used to build string for error messages
list glDither = [0.5, 0.5, -0.5, -0.5, 0.0, 0.0]; // Dither offset for landing positions so avatars don't land on top of each other
list glShuffledList = []; // Global variable for shuffled list

default
{
    state_entry()
    {
        // Turn off collision detection until calculations are complete 
        llVolumeDetect(FALSE);
        
        // Get Global Coordinates of corner of Current SIM on which the teleporter resides
        gvCurrentSimGlobal =llGetRegionCorner();
                
        //complain if there are no landmarks
        if (llGetInventoryNumber(INVENTORY_LANDMARK) == 0)
        {
            llSay(PUBLIC_CHANNEL, "There are no landmarks in me.  You need to put a landmark in me for me to work.");
        }
         //complain if there is more than one landmark
        else if (llGetInventoryNumber(INVENTORY_LANDMARK) > 1)
        {
            llSay(PUBLIC_CHANNEL, "There are TOO MANY landmarks in me.  You need to put EXACTLY ONE landmark in me for me to work.");
        }
        
        else
        {
            // Get name of the single landmark in inventory
            gsLandMarkName = llGetInventoryName(INVENTORY_LANDMARK, 0);
            // Dataserver call for local coordinates of landmark
            gkLocalCoordinateQuery = llRequestInventoryData( gsLandMarkName );
        }

    }
    
    on_rez(integer start_param) 
    { 
        llResetScript();  
    }
    
    changed( integer change )
    {
        if(change & (CHANGED_OWNER | CHANGED_REGION | CHANGED_INVENTORY))
        {
            llResetScript(); 
        }
    }
    
    dataserver(key query_id, string data)
    {

        if (query_id == gkLocalCoordinateQuery)
        {
            gvRelative_Coordinates = (vector)data;
            gvSIM_Global_Coordinates = gvRelative_Coordinates + gvCurrentSimGlobal;
            
            // Perform a bit of vector math and rounding.
            // Logically, the SIM/Region corner is an integer but must be cast as a float to be in a vector
            // Math programers may feel the urge to add a small value before rounding, 
            // to prevent erronious down-rounding but that is not necessary 
            // unless the landmark is exactly at the Region's <0.0, 0.0, 0.0> point
            // and that is an impossible landmark to create inworld because avatars
            // all have non-zero height.
            
            gvTargetSimCorner = 
            <
            256.0 * (float) ( (integer) (gvSIM_Global_Coordinates.x / 256.0)), 
            256.0 * (float) ( (integer) (gvSIM_Global_Coordinates.y / 256.0)), 
            0.0 
            >;
            
            // Local coordinates are not rounded because global coordinates are not rounded
            // Only the SIM/Region corner value has been rounded
            
            gvLocal_Coordinates = gvSIM_Global_Coordinates - gvTargetSimCorner; 
            if (giDebug)
            {  
                llSay (PUBLIC_CHANNEL, "gvCurrentSimGlobal:" + (string)gvCurrentSimGlobal);
                llSay (PUBLIC_CHANNEL, "gvSIM_Global_Coordinates:" + (string) gvSIM_Global_Coordinates);
                llSay (PUBLIC_CHANNEL, "gvTargetSimCorner:" + (string)gvTargetSimCorner);
                llSay (PUBLIC_CHANNEL, "gvLocal_Coordinates:" + (string)gvLocal_Coordinates);
            }
            
            // Prepare object to detect collision_start events when interpenetrating. 
            llVolumeDetect(TRUE);
        }
    }
    
    collision_start(integer detected)
    {
        llRequestExperiencePermissions(llDetectedKey(0), "");
        // Shuffle dither list while server is checking permissions in parallel
        glShuffledList = llListRandomize ( glDither, 1) ; // randomize order of offset values, all of which are float type
         
    }
    
    experience_permissions( key agent_id )
    {
        // teleport to local coordinates within SIM / Region, with random dither offset to local coordinates 
        llTeleportAgentGlobalCoords( agent_id, gvTargetSimCorner,
                                      (<gvLocal_Coordinates.x + llList2Float( glShuffledList, 0 ), 
                                        gvLocal_Coordinates.y + llList2Float( glShuffledList, 1 ), 
                                        gvLocal_Coordinates.z> ),
                                        gvLookat);
    }
    
    experience_permissions_denied( key agent_id, integer reason )
    {
        gsErrorMessage = "Teleport Denied: " + llGetExperienceErrorMessage(reason) + ". ";
        if (reason == 1) gsErrorMessage += "The call failed due to too many recent calls."; 
        else if (reason == 2) gsErrorMessage += "The region currently has experiences disabled."; 
        else if (reason == 3) gsErrorMessage += "One of the string arguments was too big to fit in the key-value store."; 
        else if (reason == 4) gsErrorMessage += "Experience permissions were denied by the user."; 
        else if (reason == 5) gsErrorMessage += "This script is not associated with an experience."; 
        else if (reason == 6) gsErrorMessage += "The sim was unable to verify the validity of the experience. Retrying after a short wait is advised."; 
        else if (reason == 7) gsErrorMessage += "The script is associated with an experience that no longer exists."; 
        else if (reason == 8) gsErrorMessage += "The experience owner has temporarily disabled the experience."; 
        else if (reason == 9) gsErrorMessage += "The experience has been suspended by Linden Lab customer support."; 
        else if (reason == 10) gsErrorMessage += "An unknown error not covered by any of the other predetermined error states."; 
        else if (reason == 11) gsErrorMessage += "An attempt to write data to the key-value store failed due to the data quota being met."; 
        else if (reason == 12) gsErrorMessage += "The key-value store is currently disabled on this region."; 
        else if (reason == 13) gsErrorMessage += "Unable to communicate with the key-value store."; 
        else if (reason == 14) gsErrorMessage += "The requested key does not exist."; 
        else if (reason == 15) gsErrorMessage += "A checked update failed due to an out of date request."; 
        else if (reason == 16) gsErrorMessage += "The content rating of the experience exceeds that of the region."; 
        else if (reason == 17) gsErrorMessage += "The experience is blocked or not enabled for this land."; 
        else if (reason == 18) gsErrorMessage += "The request for experience permissions was ignored."; 

        llSay(PUBLIC_CHANNEL, gsErrorMessage);
        llRegionSayTo( agent_id, PUBLIC_CHANNEL, gsErrorMessage );  
    }
}

 

Edited by Erwin Solo
  • Like 2
  • Thanks 1

Share this post


Link to post
Share on other sites
Posted (edited)
On 11/03/2018 at 8:55 PM, Erwin Solo said:

 

I completely agree.  I scripted two versions.  I first scripted a version using llTeleportAgent( key avatar, string landmark, vector position, vector look_at ) , but it was failing about 50% of the time.  I couldn't figure out was was wrong.....

 

I was playing with this and the failure seems to be that subsequent collision events fail to trigger. Fixed it by making the "portal" a thin plane that the avatar passes though very quickly and trigger the teleport on both collision start and end. A much simpler script that works 100% of the time.

    collision_start(integer num_detected)
    { 
        if (llDetectedType(0) == (AGENT | ACTIVE)) {
            llRequestExperiencePermissions(llDetectedKey(0), "");
        }
    }
    collision_end(integer num_detected)
    { 
        if (llDetectedType(0) == (AGENT | ACTIVE)) {
            llRequestExperiencePermissions(llDetectedKey(0), "");
        }
    }   
    experience_permissions(key agent) {
        llTeleportAgent(agent, llGetInventoryName(INVENTORY_LANDMARK, 0), ZERO_VECTOR, ZERO_VECTOR);
    }

Edit - To add. If the experience teleport occurs on collision_start, no collision_end event is triggered , so duplicate teleport do not occur.

 

 

Edited by CoffeeDujour
  • Like 2
  • Thanks 1

Share this post


Link to post
Share on other sites

A few people have contacted me saying that they are not scripters but that they want to use this script, and needed support.  To make such interaction easier, I put a free version of the script embedded in two objects: a Door (for collision use) and a Teleporter Pad (for touch/sit use). Listing URL: http://marketplace.secondlife.com/p/ES-Bump-Teleporter-Experience-Based-Teleport-even-Off-SIM-Gridwide/14209701

  • Like 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×