Difference between revisions of "Random AV Profile Projector"

From Second Life Wiki
Jump to navigation Jump to search
m (<lsl> tag to <source>)
 
(20 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{LSL Header}}
{{LSL Header}}


'''~ RANDOM AV PROFILE PICTURE PROJECTOR v5.1 by Debbie Trilling ~'''
'''~ RANDOM AV PROFILE PICTURE PROJECTOR v5.4.5 by Debbie Trilling ~'''
 
'''Set-up, configuration and operation Help:''' http://wiki.secondlife.com/wiki/Talk:Random_AV_Profile_Projector


'''Profile:''' http://wiki.secondlife.com/wiki/User:Debbie_Trilling
'''Profile:''' http://wiki.secondlife.com/wiki/User:Debbie_Trilling


<lsl>
{{World.secondlife.com changes}}
// ~ RANDOM AV PROFILE PICTURE PROJECTOR v5.1 by Debbie Trilling ~
 
<source lang="lsl2">
// ~ RANDOM PROFILE PROJECTOR v5.4.5.20091126 by Debbie Trilling ~
   
   
// *** This script randomly selects an AV from a crowd & then displays their
// *** This script randomly selects an AV from a crowd & then displays their
Line 12: Line 16:
   
   
// Free to use as you wish by under condition that the title and this introduction remain in place,
// Free to use as you wish by under condition that the title and this introduction remain in place,
// and that due credit continues to be given to Moriash Moreau, Jana Kamachi and Solar Alter, and
// and that due credit continues to be given to Moriash Moreau, Coder Kas and
// Debbie Trilling.
// Debbie Trilling.
// 2009-11-24 VD - mod to use <meta> tag, to work around WEB-1383
// 2009-11-26 VD - add fallback to <img> tag in case the profile changes are reverted
   
   
// TOUCH to switch ON and OFF
// TOUCH to switch ON and OFF
// ONLINE HELP AT:  http://wiki.secondlife.com/wiki/Talk:Random_AV_Profile_Projector
   
   
// ** PARAMETERS THAT YOU CAN CHANGE **
// ** PARAMETERS THAT YOU CAN CHANGE **
Line 23: Line 32:
// GENERAL PARAMETERS
// GENERAL PARAMETERS
//************************
//************************
// listen channel for Owner
integer OwnerChannel = 54321;
// set the maximum number of entries in the 'Exclude List' at any one time
integer ExcludeListSize = 30;
// the number of seconds that a listen remains open before timing-out & automatically closing
float DialogTimeout = 20.00;
// how often in seconds the sensor fires
// how often in seconds the sensor fires
float RepeatTime = 35.00;
float RepeatTime = 35.00;
Line 34: Line 53:
integer TotalNoScansAllowed = 20;
integer TotalNoScansAllowed = 20;
   
   
// sets whether the DefaultTexture will be textured/projected when the toy is switched OFF. 'TRUE' to texture/project; 'FALSE' to have no texturing/projection when off
// texture palette of UUID's. One will be randomly selected for display when an AV without a profile pic is selected
integer ProjectDefaultTexture = TRUE;
list DefaultTexturePalette = ["8fb9ad84-4183-51df-f566-9b21c3a610fe", "1201c3de-d022-c0a5-56bd-bc49ab971726", "c3eebd9e-ee92-a16f-f906-bc275928df86"];
   
   
// texture palette of UUID's. One will be randomly selected for display when an AV without a profile pic is selected
// sets whether the DefaultTexturePalette will be used to texture/project when the toy is switched OFF. 'TRUE' to texture/project; 'FALSE' to have no texturing/projection when off
list DefaultTexture = ["7cfd684e-2141-941c-eac8-bd439f0d5a9f", "d02531dd-491c-45b5-2cab-2e47ec81ec0d", "c3eebd9e-ee92-a16f-f906-bc275928df86"];
integer EmployDefaultTexture = TRUE;
   
   
string profile_key_prefix = "<meta name=\"imageid\" content=\"";
string profile_img_prefix = "<img alt=\"profile image\" src=\"http://secondlife.com/app/image/";
integer profile_key_prefix_length; // calculated from profile_key_prefix in InitialiseObject()
integer profile_img_prefix_length; // calculated from profile_img_prefix in InitialiseObject()
   
   
//************************
//************************
// PARTICLE EMISSION PARAMETERS
// PARTICLE EMISSION PARAMETERS
//************************
//************************
// set to TRUE to display the profile picture as a particle 'holographic' image above the prim
// set to TRUE to display the profile picture as a particle 'holographic' image above the prim
integer DisplayBanner = TRUE;
integer DisplayBanner = TRUE;
Line 57: Line 82:
// PRIM TEXTURE PARAMETERS
// PRIM TEXTURE PARAMETERS
//************************
//************************
// set to TRUE to texture the prim with the profile picture on ALL_SIDES
// set to TRUE to texture the prim with the profile picture on ALL_SIDES
integer TexturePrim = TRUE;
integer TexturePrim = TRUE;
   
   
// the following 'Prim*' parameters effect the prim only if ProjectDefaultTexture and/or TexturePrim = FALSE
// the following 'Prim*' parameters effect the prim only if ("EmployDefaultTexture = FALSE") OR ("EmployDefaultTexture = TRUE" and "TexturePrim=FALSE")
// if either = TRUE then the prim is automatically set to solid blank white with full bright
// if TexturePrim = TRUE then the prim is automatically set to solid blank white no shiny with full bright as this is usually the best surface to display the profile picture
// texture to use for the prim when toy is OFF
// texture to use for the prim when toy is OFF
key PrimTexture = "5748decc-f629-461c-9a36-a35a221fe21f";
key PrimUUIDTexture = "5748decc-f629-461c-9a36-a35a221fe21f";
   
   
// set to TRUE to turn on Full Bright on ALL_SIDES when the toy is OFF
// set to TRUE to turn on Full Bright on ALL_SIDES when the toy is OFF
Line 73: Line 100:
// set the alpha of the prim from 0.0 (clear) to 1.0 (solid) for when toy is OFF
// set the alpha of the prim from 0.0 (clear) to 1.0 (solid) for when toy is OFF
float PrimAlpha = 1.00;
float PrimAlpha = 1.00;
// set the degree of 'shininess' to apply to the prim "0" = None, "1" = Low, "2" = medium, "3" = high
integer PrimShine = 3;
//************************
// FLOATING TEXT PARAMETERS
//************************
// set to TRUE for floating text above the prim; FALSE to disable the floating text
integer ApplyFloatingText = TRUE;
// set the text to be displayed
string FloatingText = "'Touch' for more information";
// set the text colour
vector FloatingTextColour = <1.0,1.0,0.0>;
// set the text alpha
float FloatingTextAlpha = 0.8;
//************************
// ROTATION PARAMETERS
//************************
// if TRUE, applies a slow rotation to the prim when the toy is swtiched ON and TexturePrim = TRUE; FALSE to disable rotation
integer ApplyRotation = FALSE;
   
   
   
   
Line 78: Line 132:
// SHOUTOUT PARAMETERS
// SHOUTOUT PARAMETERS
//************************
//************************
// set to 'TRUE' to give a 'ShoutOut' to the AV once they have been selected; 'FALSE' for no 'ShoutOut'
// set to 'TRUE' to give a 'ShoutOut' to the AV once they have been selected; 'FALSE' for no 'ShoutOut'
integer ShoutOut = TRUE;
integer ShoutOut = TRUE;
Line 87: Line 142:
   
   
   
   
//************************  
//************************
// ** DO NOT CHANGE BELOW THIS LINE **
// ** DO NOT CHANGE BELOW THIS LINE **
//************************  
//************************
   
   
string URL_FORUMTHREAD = "http://forums.secondlife.com/showthread.php?t=225692";
string URL_WIKIPAGE = "http://wiki.secondlife.com/wiki/User:Debbie_Trilling";
string URL_RESIDENT = "http://world.secondlife.com/resident/";
key LastTexture = "";
integer Power = FALSE;
integer Power = FALSE;
integer ListenChannel;
integer OwnerListenChannel;
integer NoSensorCounter = 0;
integer NoSensorCounter = 0;
key AVKey = "";
key AVKey = "";
key DetectedUser = "";
key DetectedUser = "";
key ObjectOwner = "";
key ObjectOwner = "";
key LastTexture = "";
string OwnerName = "";
string OwnerName = "";
string ObjectName = "Profile Projector";
string ObjectName = "Profile Projector";
string Author = "Debbie Trilling";
string Author = "Debbie Trilling";
string Supplier = "The Particle Crucible";
string Supplier = "The Particle Crucible";
string Version = " v5.1";
string Version = " v5.4.5.20091126";
integer ListenChannel;
string OwnerListenText = "OpenListen";
float DialogTimeout = 20.0;
string SelfExcludedSuffix = "**";
list KillJoyListing = [];
string PowerText = "On";
 
list ExcludeListing = [];
 
   
   
   
   
Line 120: Line 177:
     llSay(0, llKey2Name(AVKey) + ShoutOutText);
     llSay(0, llKey2Name(AVKey) + ShoutOutText);
   
   
}
AnnounceWelcome()
{
    llOwnerSay(
        "\nThank you for your interest in this " + ObjectName + " "
            + Version + " created by " + Author + " at " + Supplier + ". \nHelp setting up, configuring and operating the "
        + ObjectName + " can be gotton at http://wiki.secondlife.com/wiki/Talk:Random_AV_Profile_Projector \nTOUCH the " + ObjectName + " to operate it.");
}
InitialiseObject()
{
    llParticleSystem([]);
    StopRotation();
    ObjectOwner = llGetOwner();
    OwnerName = llKey2Name(ObjectOwner);
    llSetObjectName(ObjectName + Version);
    llSetObjectDesc("Supplied free by " + Author + "'s " + Supplier);
    CloseAllListens();
    profile_key_prefix_length = llStringLength(profile_key_prefix);
    profile_img_prefix_length = llStringLength(profile_img_prefix);
}
SetFloatingText()
{
    if (ApplyFloatingText)
    {
        llSetText(FloatingText, FloatingTextColour, FloatingTextAlpha);
    }
    else
    {
        llSetText("",<1.0,1.0,1.0>,0.0);
    }
}
}
   
   
Line 126: Line 219:
{
{
     // are we going to use a default texture when toy is OFF?
     // are we going to use a default texture when toy is OFF?
     if (ProjectDefaultTexture)
     if (EmployDefaultTexture)
     {  
     {
         if (TexturePrim)
         if (TexturePrim)
         {
         {
             // using a default texture; if putting texture on the prim, let's make sure it is solid white, blank. full bright
             // using a default texture
llSetPrimitiveParams([PRIM_FULLBRIGHT, ALL_SIDES, TRUE, PRIM_COLOR, ALL_SIDES, <1.0, 1.0, 1.0>, 1.0 ]);
            ApplyPrimSurface();
         }
         }
         else
         else
         {
         {
// not texturing the prim, so apply the prom preferences
            // not texturing the prim, so apply the prim preferences
             ApplyPrimPrefs();
             ApplyPrimPrefs();
         }
         }
         ParticleStart((key)llList2String(DefaultTexture, (integer)llFrand((float)llGetListLength(DefaultTexture))));
         ApplyDefaultTexture();
     }
     }
     else
     else
Line 147: Line 240:
     }
     }
}
}
ApplyPrimSurface()
{
    // putting texture on the prim, let's make sure it is solid white, blank. full bright
    llSetPrimitiveParams([PRIM_FULLBRIGHT, ALL_SIDES, TRUE, PRIM_COLOR, ALL_SIDES, <1.0, 1.0, 1.0>, 1.0, PRIM_BUMP_SHINY, ALL_SIDES, 0, 0 ]);
}
   
   
ApplyPrimPrefs()
ApplyPrimPrefs()
{
{
     llSetPrimitiveParams([PRIM_FULLBRIGHT, ALL_SIDES, PrimFullBright,
     llSetPrimitiveParams([PRIM_FULLBRIGHT, ALL_SIDES, PrimFullBright,
         PRIM_TEXTURE, ALL_SIDES, PrimTexture, <1.000000, 1.000000, 0.000000>, <0.000000, 0.000000, 0.000000>, 0.000000, PRIM_COLOR, ALL_SIDES, PrimColour, PrimAlpha ]);
         PRIM_TEXTURE, ALL_SIDES, PrimUUIDTexture, <1.000000, 1.000000, 0.000000>, <0.000000, 0.000000, 0.000000>, 0.000000, PRIM_COLOR, ALL_SIDES, PrimColour, PrimAlpha, PRIM_BUMP_SHINY, ALL_SIDES, PrimShine, 0 ]);
}
StartUp()
{
    Power = TRUE;
    PowerText = "Off";
    llSensorRepeat("",NULL_KEY,AGENT,Range,PI,RepeatTime);
    NoSensorCounter = 0;
    ApplyPrimUpdate();
    llOwnerSay("\nThe " + ObjectName + " is now switched ON. Please wait...");
}
ApplyPrimUpdate()
{
    if (TexturePrim)
    {
        ApplyPrimSurface();
        if (ApplyRotation)
        {
            llTargetOmega(<0.0,0.0,1.0>, 0.2, PI);
        }
    }
}
ApplyDefaultTexture()
{
    ApplySelectedTexture((key)llList2String(DefaultTexturePalette, (integer)llFrand((float)llGetListLength(DefaultTexturePalette))));
}
string RemainingExcludeSlots()
{
    string RemainingSlots = (string)(ExcludeListSize - llGetListLength(ExcludeListing)) + " slots are now available.";
    return RemainingSlots;
}
string DeriveName(string messagecapture)
{
    string DerivedName = llGetSubString(llStringTrim(messagecapture,STRING_TRIM),8,llStringLength(llStringTrim(messagecapture,STRING_TRIM)));
    return DerivedName;
}
integer DeriveNamePosition(string messagecapture)
{
    integer DerivedNamePosition = llListFindList(ExcludeListing, (list)llGetSubString(llStringTrim(messagecapture,STRING_TRIM),8,llStringLength(llStringTrim(messagecapture,STRING_TRIM))));
    return DerivedNamePosition;
}
}
   
   
   
   
ParticleStart(key texture)
ApplySelectedTexture(key texture)
{
{
     if (DisplayBanner)
     if (DisplayBanner)
     {
     {
        // make the particle banner if required
         //core code by Moriash Moreau. Adapted to suit by Debbie Trilling
         //core code by Moriash Moreau. Adapted to suit by Debbie Trilling
         llParticleSystem([
         llParticleSystem([
Line 189: Line 342:
}
}
   
   
AnnounceWelcome()
ShutDown()
{
    Power = FALSE;
    PowerText = "On";
    CloseAllListens();
    llSensorRemove();
    StopRotation();
    ProjectTexture();
    llOwnerSay("\nThe " + ObjectName + " is now switched OFF.");
}
StopRotation()
{
    llTargetOmega(<0.0,0.0,0.0>, 0.0, PI);
}
CloseAllListens()
{
{
     llOwnerSay(
     CloseUserListen();
        "\nThank you for your interest in this product created by Debbie Trilling at The Particle Crucible.");
    llListenRemove(OwnerListenChannel);
    OwnerListenText = "OpenListen";
}
}
   
   
   
   
ShutDown()
CloseUserListen()
{
{
     llSensorRemove();
     llSetTimerEvent(0.0);
llListenRemove(ListenChannel);
    llListenRemove(ListenChannel);
    Power = FALSE;
    ProjectTexture();
}
}
   
   
Line 211: Line 382:
     {
     {
         // reset script on rez
         // reset script on rez
        AnnounceWelcome();
         llResetScript();
         llResetScript();
     }
     }
Line 220: Line 390:
         {
         {
             // reset script on change of owner
             // reset script on change of owner
            AnnounceWelcome();
             llResetScript();
             llResetScript();
         }
         }
Line 228: Line 397:
     {
     {
         //initialise system
         //initialise system
         llParticleSystem([]);
         InitialiseObject();
         ObjectOwner = llGetOwner();
         SetFloatingText();
        OwnerName = llKey2Name(ObjectOwner);
        llSetObjectName(ObjectName + Version);
        llSetObjectDesc("Supplied free by " + Author + "'s " + Supplier);
         ProjectTexture();
         ProjectTexture();
         llOwnerSay("\nTOUCH the " + ObjectName + " to switch it ON and OFF.");
         AnnounceWelcome();
     }
     }
   
   
     touch_start(integer total_number)
     touch_start(integer total_number)
     {
     {
         if (llDetectedKey(0) == ObjectOwner)
         DetectedUser = llDetectedKey(0);
        list MenuItems = ["LearnMore", "GetScript", "Help"];
        string MenuText = "MAIN MENU: Please make a selection within " + (string)llFloor(DialogTimeout)
            + " seconds.\n- LearnMore: Read the forum thread on this product\n- GetScript: Get yourself the latest version of this free script\n- Help: Link to the "
            + ObjectName + " Help page";
        if (DetectedUser == ObjectOwner)
         {
         {
             // operation by Owner Only
             // touched by Owner
             if (Power)
             if (Power)
             {
             {
                 // touch to OFF
                 MenuItems = [PowerText, OwnerListenText] + MenuItems;
                ShutDown();
                 MenuText = MenuText + "\n- Off: Switch off \n- Open/CloseListen: Opens/Closes Owner listen channel " + (string)OwnerChannel;
                 llOwnerSay("\nThe " + ObjectName + " is now switched OFF.");
             }
             }
             else
             else
             {
             {
                 // touch to ON
                 MenuItems = (list)PowerText + MenuItems;
                Power = TRUE;
                 MenuText = MenuText + "\n- On: Switch on";
                NoSensorCounter = 0;
                llSensorRepeat("",NULL_KEY,AGENT,Range,PI,RepeatTime);
                 llOwnerSay("\nThe " + ObjectName + " is now switched ON. Please wait...");
             }
             }
         }
         }
Line 260: Line 429:
         {
         {
             // touched by someone other than Owner. Send them a message & a dialog box of options
             // touched by someone other than Owner. Send them a message & a dialog box of options
DetectedUser = llDetectedKey(0);
   
llInstantMessage(DetectedUser, "\nThank you for your interest in the " + ObjectName + " created by " + Author + "\nThe dialog menu offers a number of options.");
             // if they placed their own name on 'Exclude List', so give opportunity to clear their name, else give opportunity to exclude their name
integer CommChannel = (-200000 - ((integer)llFrand(12345) * -1));
            if (llListFindList(ExcludeListing, (list)(llKey2Name(AVKey) + SelfExcludedSuffix)) != -1 )
list MenuItems = ["LearnMore","GetScript"];
            {
string MenuText = "MAIN MENU: Please make a selection within " + (string)llFloor(DialogTimeout) + " seconds.\n- LearnMore: Read the forum thread on this product\n- GetScript: Get yourself a free copy of this script";
                // they placed themself on the 'Exclude List' so are therefore allowed to clear their name
             // if already on 'Exclude List', give opportunity to clear their name, else give opportunity to exclude their name
                MenuItems = (list)"IncludeMe" + MenuItems;
if (llListFindList(KillJoyListing, (list)llKey2Name(AVKey)) != -1 )
                MenuText =  MenuText + "\n- IncludeMe: Have the " + ObjectName + " remove your name from the 'Exclude List'";
{
            }
// they are on the 'Exclude List' so give opportunity to clear their name
            else
MenuItems = MenuItems + (list)"IncludeMe";
            {
MenuText =  MenuText + "\n- IncludeMe: Have the " + ObjectName + " include you in on the fun!";
                // they have not placed themself on the 'Exclude List', so check whether the Owner has already done it
}
                if (llListFindList(ExcludeListing, (list)llKey2Name(AVKey)) == -1 )
else
                {
{
                    // neither they themself nor the Owner has previously excluded them, so give them the opportunity to exclude themselves now
// they are not on the 'Exclude List' so give opportunity to add their name
                    MenuItems = (list)"ExcludeMe" + MenuItems;
MenuItems = MenuItems + (list)"ExcludeMe";
                    MenuText =  MenuText + "\n- ExcludeMe: Have your name added to the " + ObjectName + "'s 'Exclude List'";
MenuText =  MenuText + "\n- ExcludeMe: Have the " + ObjectName + " ignore your presence";
                }
}
            }
ListenChannel = llListen(CommChannel, "", DetectedUser, "");
            llInstantMessage(DetectedUser, "\nThank you for your interest in the " + ObjectName + " created by " + Author + "\nThe dialog menu offers a number of options.");
llDialog(DetectedUser, MenuText, MenuItems, CommChannel);
llSetTimerEvent(DialogTimeout);
         }
         }
        // generate the dialog menu
        integer CommChannel = (-200000 - ((integer)llFrand(12345) * -1));
        ListenChannel = llListen(CommChannel, "", DetectedUser, "");
        llDialog(DetectedUser, MenuText, MenuItems, CommChannel);
        llSetTimerEvent(DialogTimeout);
     }
     }
   
   
Line 289: Line 461:
         // save the AV key in case it is needed for a 'ShoutOut'
         // save the AV key in case it is needed for a 'ShoutOut'
         AVKey = llDetectedKey((integer)llFrand(total_number));
         AVKey = llDetectedKey((integer)llFrand(total_number));
         // core code by Jana Kamachi and Solar Alter. Adapted to suit by Debbie Trilling
         // core code by Coder Kas. Adapted to suit by Debbie Trilling
        string URL_RESIDENT = "http://world.secondlife.com/resident/";
         llHTTPRequest( URL_RESIDENT + (string)AVKey,[HTTP_METHOD,"GET"],"");
         llHTTPRequest( URL_RESIDENT + (string)AVKey,[HTTP_METHOD,"GET"],"");
     }
     }
Line 306: Line 479:
         else
         else
         {
         {
             ParticleStart((key)llList2String(DefaultTexture, (integer)llFrand((float)llGetListLength(DefaultTexture))));
             ApplyDefaultTexture();
         }
         }
     }
     }
Line 313: Line 486:
     http_response(key req,integer stat, list met, string body)
     http_response(key req,integer stat, list met, string body)
     {
     {
         // core code by Jana Kamachi and Solar Alter. Adapted to suit by Debbie Trilling
         // core code by Coder Kas. Adapted to suit by Debbie Trilling
         integer s1 = 0;
         integer s1 = llSubStringIndex(body, profile_key_prefix);
         integer s2 = 0;
         integer s1l = profile_key_prefix_length;
         integer s1l= 0;
         if(s1 == -1)
        integer s2l= -3;
         { // second try with img tag
         s1 = llSubStringIndex(body,"<img alt=\"profile image\" src=\"http://secondlife.com/app/image/");
            s1 = llSubStringIndex(body, profile_img_prefix);
        s1l = llStringLength("<img alt=\"profile image\" src=\"http://secondlife.com/app/image/");
            s1l = profile_img_prefix_length;
         s2 = llSubStringIndex(body,"\" class=\"parcelimg\" />");
         }
 
         if(s1 == -1)
         if(s1 == -1)
         {
         {
             // selected AV doesn't have a profile picture, so use the default instead
             // selected AV doesn't have a profile picture, so use the default instead
             ParticleStart((key)llList2String(DefaultTexture, (integer)llFrand((float)llGetListLength(DefaultTexture))));
             ApplyDefaultTexture();
         }
         }
         else
         else
         {
         {
            key NewTexture = (key)llGetSubString(body,s1+s1l,s1+s1l+35);
             //check whether this was the texture used last time
             //check whether this was the texture used last time
             if ((key)llGetSubString(body,s1+s1l,s2+s2l) == LastTexture)
             if (NewTexture == LastTexture || NewTexture == NULL_KEY)
             {
             {
                 // same profile pic as last time. so display a random default instead
                 // same profile pic as last time. so display a random default instead
                 ParticleStart((key)llList2String(DefaultTexture, (integer)llFrand((float)llGetListLength(DefaultTexture))));
                 ApplyDefaultTexture();
                 // clear the last texture out
                 // clear the last texture out
                 LastTexture = "";
                 LastTexture = "";
Line 339: Line 514:
             else
             else
             {
             {
// are they on the KillJoyListing? if so, we had better pander to their delicate sensibilities & display a random default texture instead
                // are they on the ExcludeListing, with or without a suffix? if so, display a random default texture instead
if (llListFindList(KillJoyListing, (list)llKey2Name(AVKey)) != -1 )
                if ((llListFindList(ExcludeListing, (list)llKey2Name(AVKey)) != -1 ) || (llListFindList(ExcludeListing, (list)(llKey2Name(AVKey) + SelfExcludedSuffix)) != -1))
{
                {
// they are on the 'Exclude List'
                    // they are on the 'Exclude List'
ParticleStart((key)llList2String(DefaultTexture, (integer)llFrand((float)llGetListLength(DefaultTexture))));
                    ApplyDefaultTexture();
}
                }
else
                else
{
                {
                // different profile from last time & not on KillJoyListing, so display it
                    // different profile from last time & not on ExcludeListing, so display it
                ParticleStart((key)llGetSubString(body,s1+s1l,s2+s2l));
                    ApplySelectedTexture(NewTexture);
                // save the key for comparison purposes next time tho'
                    // save the key for comparison purposes next time tho'
                LastTexture = (key)llGetSubString(body,s1+s1l,s2+s2l);
                    LastTexture = NewTexture;
                    // give a 'ShoutOut', if set to do so
                    if (ShoutOut)
                    {
                        GiveShoutOut();
                    }
                }
            }
        }
    }
    listen(integer channel, string name, key id, string message)
    {
        if (message == "LearnMore")
        {
            string URL_FORUMTHREAD = "http://forums-archive.secondlife.com/54/1b/225692/1.html";
            llLoadURL(DetectedUser, "Thank you for choosing to learn more about the " + ObjectName + ".This link will take you to the relevant SL forum thread.", URL_FORUMTHREAD);
            CloseUserListen();
        }
        else if (message == "GetScript")
        {
            string URL_WIKIPAGE = "http://wiki.secondlife.com/wiki/User:Debbie_Trilling";
            llLoadURL(DetectedUser, "Thank you for choosing to look at the script for the " + ObjectName + ".This link will allow you to get your own free copy.", URL_WIKIPAGE);
            CloseUserListen();
        }
        else if (message == "Help")
        {
            string URL_HELPPAGE = "http://wiki.secondlife.com/wiki/Talk:Random_AV_Profile_Projector";
            llLoadURL(DetectedUser, "This link will take you to the " + ObjectName + "'s Help page.", URL_HELPPAGE);
            CloseUserListen();
        }
        else if (message == "ExcludeMe")
        {
            // as a suffix to the name, as it is the user adding their own name
            ExcludeListing = (list)(llKey2Name(DetectedUser) + SelfExcludedSuffix) + llList2List( ExcludeListing, 0, (ExcludeListSize - 2));
            llInstantMessage(DetectedUser, "You have been added to the " + ObjectName + "'s 'Exclude List'");
            CloseUserListen();
        }
        else if (message == "IncludeMe")
        {
            integer ExcludeListPosition = llListFindList(ExcludeListing, (list)(llKey2Name(DetectedUser) + SelfExcludedSuffix));
            ExcludeListing = llDeleteSubList(ExcludeListing, ExcludeListPosition, ExcludeListPosition);
            llInstantMessage(DetectedUser, "You have been removed from the " + ObjectName + "'s 'Exclude List'");
            CloseUserListen();
        }
        else if ((message == "On") && (id == ObjectOwner))
        {
            StartUp();
        }
        else if ((message == "Off") && (id == ObjectOwner))
        {
            ShutDown();
        }
        else if ((message == "OpenListen") && (id == ObjectOwner))
        {
            // open the Owner Only channel
            OwnerListenChannel = llListen(OwnerChannel, "", ObjectOwner, "");
            OwnerListenText = "CloseListen";
            llOwnerSay("Owner Only channel " + (string)OwnerChannel + " is now open for you.\n Options are: 'Exclude <AV_NAME>', 'Include <AV_NAME>', 'ClearAll' and 'List'");
        }
        else if ((message == "CloseListen") && (id == ObjectOwner))
        {
            // close the Owner Only channel
            llListenRemove(OwnerListenChannel);
            OwnerListenText = "OpenListen";
            llOwnerSay("Owner Only channel " + (string)OwnerChannel + " is now closed.");
        }
        else if (((llGetSubString(message,0,6) == "Exclude") || (llGetSubString(message,0,6) == "exclude")) && (id == ObjectOwner))
        {
            // before adding them to the 'Exclude List', check if already on it
            // they could be on the list simply as their own name, their name + a suffix, perhaps even both.
            if ((DeriveNamePosition(message) != -1 ) || (DeriveNamePosition(message + SelfExcludedSuffix) != -1))
            {
                llOwnerSay(DeriveName(message) + " already exists on the " + ObjectName + "'s 'Exclude List'.");
            }
            else
            {
                // not on the list, so add them (without a suffix, as it is the Owner doing the adding)
                string NewExcludeName = DeriveName(message);
                ExcludeListing = (list)NewExcludeName + llList2List( ExcludeListing, 0, (ExcludeListSize - 2));
                llOwnerSay(NewExcludeName + " has been added to the "
                    + ObjectName + "'s 'Exclude List'. \nThere are now " + RemainingExcludeSlots());
            }
        }
        else if (((llGetSubString(message,0,6) == "Include") || (llGetSubString(message,0,6) == "include")) && (id == ObjectOwner))
        {
            // they could be on the list simply as their own name, their name + a suffix, perhaps even both. We need to test for all scenerios
            // locate their position within in 'Exclude List', if they do exist
            integer NamePositionTest = DeriveNamePosition(message);
            integer NamePositionSuffixTest = DeriveNamePosition(message + SelfExcludedSuffix);
            // test to see if either are on the 'Exclude List'.
            if ((NamePositionTest != -1) || (NamePositionSuffixTest != -1))
            {
                // well, their name is definately on the 'Exclude list', but is it with or without a suffix? Is it both?
                // would look neater to do the next tests in an IF-IF/ELSE-ELSE, but we can save a lil memory using two IF statement (albeit with a tiny speed overhead)
                if (NamePositionTest != -1)
                {
                    // it's on without a suffix
                    ExcludeListing = llDeleteSubList(ExcludeListing, NamePositionTest, NamePositionTest);
                }
                if (NamePositionSuffixTest != -1)
                {
                    //it's on with a suffix
                    ExcludeListing = llDeleteSubList(ExcludeListing, NamePositionSuffixTest, NamePositionSuffixTest);
                }
                llOwnerSay(DeriveName(message) + " has been removed from the "
                    + ObjectName + "'s 'Exclude List'. \nThere are now " + RemainingExcludeSlots());
            }
            else
            {
                llOwnerSay(DeriveName(message) + " could not located on the " + ObjectName + "'s 'Exclude List'.");
            }
        }
        else if (((llGetSubString(message,0,7) == "ClearAll") || (llGetSubString(message,0,7) == "clearall") || (llGetSubString(message,0,8) == "clear all") || (llGetSubString(message,0,8) == "Clear all")) && (id == ObjectOwner))
        {
            ExcludeListing = [];
            llOwnerSay("The 'Exclude List' has been cleared. All " + RemainingExcludeSlots());
   
   
                // give a 'ShoutOut', if set to do so
        }
                if (ShoutOut)
        else if (((llGetSubString(message,0,3) == "List") || (llGetSubString(message,0,3) == "list")) && (id == ObjectOwner))
                {
        {
                    GiveShoutOut();
            if (llGetListLength(ExcludeListing) > 0)
                }
            {
}
                llOwnerSay("The following " + (string)llGetListLength(ExcludeListing) + " AV's are listed on the 'Exclude List'. Names ending with '" + SelfExcludedSuffix + "' chose to exclude themselves.\n"
                    + llDumpList2String(ExcludeListing, " | "));
            }
            else
            {
                llOwnerSay("No AV's are listed on the 'Exclude List'.");
             }
             }
         }
         }
        else
        {
            llInstantMessage(DetectedUser, "Unrecognised option or selection made from a timed-out menu.");
        }
    }
    timer()
    {
        CloseUserListen();
     }
     }
listen(integer channel, string name, key id, string message)
{
llSetTimerEvent(0.0);
llListenRemove(ListenChannel);
message = llToLower(message);
if (message == "learnmore")
{
llLoadURL(DetectedUser, "Thank you for choosing to learn more about the " + ObjectName + ".\nThis link will take you to the relevant SL forum thread.", URL_FORUMTHREAD);
}
else if (message == "getscript")
{
llLoadURL(DetectedUser, "Thank you for choosing to look at the script for the " + ObjectName + ".\nThis link will allow you to get your own copy.", URL_WIKIPAGE);
}
else if (message == "excludeme")
{
KillJoyListing = KillJoyListing + llKey2Name(DetectedUser);
llInstantMessage(DetectedUser, "You have been added to the 'Exclude List' and the " + ObjectName + " will now ignore your presence");
}
else if (message == "includeme")
{
KillJoyListing = llDeleteSubList(KillJoyListing, llListFindList(KillJoyListing, (list)llKey2Name(DetectedUser)), llListFindList(KillJoyListing, (list)llKey2Name(DetectedUser)));
llInstantMessage(DetectedUser, "You has been removed from the 'Exclude List' and the " + ObjectName + " looks forward to selecting you!");
}
else
{
llInstantMessage(DetectedUser, "Unrecognised option or selection made from a timed-out menu.");
}
}
timer()
{
llSetTimerEvent(0.0);
llListenRemove(ListenChannel);
}
   
   
//default end
//default end
}
}
 
</lsl>
</source>

Latest revision as of 08:43, 25 January 2015

~ RANDOM AV PROFILE PICTURE PROJECTOR v5.4.5 by Debbie Trilling ~

Set-up, configuration and operation Help: http://wiki.secondlife.com/wiki/Talk:Random_AV_Profile_Projector

Profile: http://wiki.secondlife.com/wiki/User:Debbie_Trilling

KBcaution.png Important: This script relies on data scraped from world.secondlife.com. That site, and the page format it currently serves, will probably be replaced by my.secondlife.com pages in the coming months. The new pages use a different format and have different access controls, so expect this script to stop working if and when the change is made. See WEB-3510 for details.
// ~ RANDOM PROFILE PROJECTOR v5.4.5.20091126 by Debbie Trilling ~
 
// *** This script randomly selects an AV from a crowd & then displays their
// profile picture as texture on a prim and/or a 'holographic' image projected above the prim***
 
// Free to use as you wish by under condition that the title and this introduction remain in place,
// and that due credit continues to be given to Moriash Moreau, Coder Kas and
// Debbie Trilling.
 
// 2009-11-24 VD - mod to use <meta> tag, to work around WEB-1383
// 2009-11-26 VD - add fallback to <img> tag in case the profile changes are reverted
 
// TOUCH to switch ON and OFF
 
// ONLINE HELP AT:  http://wiki.secondlife.com/wiki/Talk:Random_AV_Profile_Projector
 
// ** PARAMETERS THAT YOU CAN CHANGE **
 
 
//************************
// GENERAL PARAMETERS
//************************
 
// listen channel for Owner
integer OwnerChannel = 54321;
 
// set the maximum number of entries in the 'Exclude List' at any one time
integer ExcludeListSize = 30;
 
// the number of seconds that a listen remains open before timing-out & automatically closing
float DialogTimeout = 20.00;
 
// how often in seconds the sensor fires
float RepeatTime = 35.00;
 
// sensor range in meters. Maximum 96m but in practice 10 to 30m because of particle draw distance
float Range = 25.00;
 
// sets the number of consecutive times that the scanner is allowed to operate without having located an AV within range
// eg: if RepeatTime = 60.0 seconds and TotalNoScansAllowed = 30, then the toy will operate for 1800 seconds (60x30, or 30 minutes) without locating
// anyone before it automatically powers down. Set to '0' to disable the auto-off function
integer TotalNoScansAllowed = 20;
 
// texture palette of UUID's. One will be randomly selected for display when an AV without a profile pic is selected
list DefaultTexturePalette = ["8fb9ad84-4183-51df-f566-9b21c3a610fe", "1201c3de-d022-c0a5-56bd-bc49ab971726", "c3eebd9e-ee92-a16f-f906-bc275928df86"];
 
// sets whether the DefaultTexturePalette will be used to texture/project when the toy is switched OFF. 'TRUE' to texture/project; 'FALSE' to have no texturing/projection when off
integer EmployDefaultTexture = TRUE;
 

string profile_key_prefix = "<meta name=\"imageid\" content=\"";
string profile_img_prefix = "<img alt=\"profile image\" src=\"http://secondlife.com/app/image/";
integer profile_key_prefix_length; // calculated from profile_key_prefix in InitialiseObject()
integer profile_img_prefix_length; // calculated from profile_img_prefix in InitialiseObject()
 
//************************
// PARTICLE EMISSION PARAMETERS
//************************
 
// set to TRUE to display the profile picture as a particle 'holographic' image above the prim
integer DisplayBanner = TRUE;
 
// width size in meters of the projected image (max 4.00)
float Size = 2.50;
 
// height above object the centre of projected image will be (theoretical max. 50.0, in practice 2.0 to 10.0))
float Height = 2.50;
 
 
//************************
// PRIM TEXTURE PARAMETERS
//************************
 
// set to TRUE to texture the prim with the profile picture on ALL_SIDES
integer TexturePrim = TRUE;
 
// the following 'Prim*' parameters effect the prim only if ("EmployDefaultTexture = FALSE") OR ("EmployDefaultTexture = TRUE" and "TexturePrim=FALSE")
// if TexturePrim = TRUE then the prim is automatically set to solid blank white no shiny with full bright as this is usually the best surface to display the profile picture
 
// texture to use for the prim when toy is OFF
key PrimUUIDTexture = "5748decc-f629-461c-9a36-a35a221fe21f";
 
// set to TRUE to turn on Full Bright on ALL_SIDES when the toy is OFF
integer PrimFullBright = FALSE;
 
// vector for the prim colour when toy is OFF
vector PrimColour = <0.0, 0.0, 0.0>;
 
// set the alpha of the prim from 0.0 (clear) to 1.0 (solid) for when toy is OFF
float PrimAlpha = 1.00;
 
// set the degree of 'shininess' to apply to the prim "0" = None, "1" = Low, "2" = medium, "3" = high
integer PrimShine = 3;
 
 
//************************
// FLOATING TEXT PARAMETERS
//************************
// set to TRUE for floating text above the prim; FALSE to disable the floating text
integer ApplyFloatingText = TRUE;
 
// set the text to be displayed
string FloatingText = "'Touch' for more information";
 
// set the text colour
vector FloatingTextColour = <1.0,1.0,0.0>;
 
// set the text alpha
float FloatingTextAlpha = 0.8;
 
 
//************************
// ROTATION PARAMETERS
//************************
 
// if TRUE, applies a slow rotation to the prim when the toy is swtiched ON and TexturePrim = TRUE; FALSE to disable rotation
integer ApplyRotation = FALSE;
 
 
//************************
// SHOUTOUT PARAMETERS
//************************
 
// set to 'TRUE' to give a 'ShoutOut' to the AV once they have been selected; 'FALSE' for no 'ShoutOut'
integer ShoutOut = TRUE;
 
// text to 'ShoutOut' when an AV's profile is projected. Text will be preceeded by their name, eg: "<AV Name>'s face is up in lights!"
string ShoutOutText = "'s face is up in lights!";
 
 
 
 
//************************
// ** DO NOT CHANGE BELOW THIS LINE **
//************************
 
 
 
 
integer Power = FALSE;
integer ListenChannel;
integer OwnerListenChannel;
integer NoSensorCounter = 0;
key AVKey = "";
key DetectedUser = "";
key ObjectOwner = "";
key LastTexture = "";
string OwnerName = "";
string ObjectName = "Profile Projector";
string Author = "Debbie Trilling";
string Supplier = "The Particle Crucible";
string Version = " v5.4.5.20091126";
string OwnerListenText = "OpenListen";
string SelfExcludedSuffix = "**";
string PowerText = "On";
list ExcludeListing = [];
 
 
 
GiveShoutOut()
{
    // any interaction with selected AV (give Inventory items etc) can safely be done from this function
    // this function will only execute if ShoutOut == TRUE
 
    //although fondly calling it a 'ShoutOut', it actually makes more sense to keep within the 20m range of llSay
    llSay(0, llKey2Name(AVKey) + ShoutOutText);
 
}
 
 
AnnounceWelcome()
{
    llOwnerSay(
        "\nThank you for your interest in this " + ObjectName + " "
            + Version + " created by " + Author + " at " + Supplier + ". \nHelp setting up, configuring and operating the "
        + ObjectName + " can be gotton at http://wiki.secondlife.com/wiki/Talk:Random_AV_Profile_Projector \nTOUCH the " + ObjectName + " to operate it.");
}
 
 
InitialiseObject()
{
    llParticleSystem([]);
    StopRotation();
    ObjectOwner = llGetOwner();
    OwnerName = llKey2Name(ObjectOwner);
    llSetObjectName(ObjectName + Version);
    llSetObjectDesc("Supplied free by " + Author + "'s " + Supplier);
    CloseAllListens();
    profile_key_prefix_length = llStringLength(profile_key_prefix);
    profile_img_prefix_length = llStringLength(profile_img_prefix);
}
 
 
SetFloatingText()
{
    if (ApplyFloatingText)
    {
        llSetText(FloatingText, FloatingTextColour, FloatingTextAlpha);
    }
    else
    {
        llSetText("",<1.0,1.0,1.0>,0.0);
    }
}
 
 
ProjectTexture()
{
    // are we going to use a default texture when toy is OFF?
    if (EmployDefaultTexture)
    {
        if (TexturePrim)
        {
            // using a default texture
            ApplyPrimSurface();
        }
        else
        {
            // not texturing the prim, so apply the prim preferences
            ApplyPrimPrefs();
        }
        ApplyDefaultTexture();
    }
    else
    {
        // we're not doing anything when the toy is OFF; change the prim to user preferences
        llParticleSystem([]);
        ApplyPrimPrefs();
    }
}
 
 
ApplyPrimSurface()
{
    // putting texture on the prim, let's make sure it is solid white, blank. full bright
    llSetPrimitiveParams([PRIM_FULLBRIGHT, ALL_SIDES, TRUE, PRIM_COLOR, ALL_SIDES, <1.0, 1.0, 1.0>, 1.0, PRIM_BUMP_SHINY, ALL_SIDES, 0, 0 ]);
}
 
 
ApplyPrimPrefs()
{
    llSetPrimitiveParams([PRIM_FULLBRIGHT, ALL_SIDES, PrimFullBright,
        PRIM_TEXTURE, ALL_SIDES, PrimUUIDTexture, <1.000000, 1.000000, 0.000000>, <0.000000, 0.000000, 0.000000>, 0.000000, PRIM_COLOR, ALL_SIDES, PrimColour, PrimAlpha, PRIM_BUMP_SHINY, ALL_SIDES, PrimShine, 0 ]);
}
 
 
StartUp()
{
    Power = TRUE;
    PowerText = "Off";
    llSensorRepeat("",NULL_KEY,AGENT,Range,PI,RepeatTime);
    NoSensorCounter = 0;
    ApplyPrimUpdate();
    llOwnerSay("\nThe " + ObjectName + " is now switched ON. Please wait...");
}
 
 
ApplyPrimUpdate()
{
    if (TexturePrim)
    {
        ApplyPrimSurface();
 
        if (ApplyRotation)
        {
            llTargetOmega(<0.0,0.0,1.0>, 0.2, PI);
        }
    }
}
 
ApplyDefaultTexture()
{
    ApplySelectedTexture((key)llList2String(DefaultTexturePalette, (integer)llFrand((float)llGetListLength(DefaultTexturePalette))));
}
 
 
string RemainingExcludeSlots()
{
    string RemainingSlots = (string)(ExcludeListSize - llGetListLength(ExcludeListing)) + " slots are now available.";
    return RemainingSlots;
}
 
 
string DeriveName(string messagecapture)
{
    string DerivedName = llGetSubString(llStringTrim(messagecapture,STRING_TRIM),8,llStringLength(llStringTrim(messagecapture,STRING_TRIM)));
    return DerivedName;
}
 
 
integer DeriveNamePosition(string messagecapture)
{
    integer DerivedNamePosition = llListFindList(ExcludeListing, (list)llGetSubString(llStringTrim(messagecapture,STRING_TRIM),8,llStringLength(llStringTrim(messagecapture,STRING_TRIM))));
    return DerivedNamePosition;
}
 
 
ApplySelectedTexture(key texture)
{
    if (DisplayBanner)
    {
        // make the particle banner if required
        //core code by Moriash Moreau. Adapted to suit by Debbie Trilling
        llParticleSystem([
            PSYS_PART_FLAGS, 0,
            PSYS_SRC_PATTERN, 4,
            PSYS_PART_START_ALPHA, 0.50,
            PSYS_PART_END_ALPHA, 0.50,
            PSYS_PART_START_COLOR, <1.0,1.0,1.0>,
            PSYS_PART_END_COLOR, <1.0,1.0,1.0>,
            PSYS_PART_START_SCALE, <Size * 1.6 ,Size,0.00>,
            PSYS_PART_END_SCALE, <Size * 1.6,Size,0.00>,
            PSYS_PART_MAX_AGE, 1.20,
            PSYS_SRC_MAX_AGE, 0.00,
            PSYS_SRC_ACCEL, <0.0,0.0,0.0>,
            PSYS_SRC_ANGLE_BEGIN, 0.00,
            PSYS_SRC_ANGLE_END, 0.00,
            PSYS_SRC_BURST_PART_COUNT, 8,
            PSYS_SRC_BURST_RADIUS, Height,
            PSYS_SRC_BURST_RATE, 0.10,
            PSYS_SRC_BURST_SPEED_MIN, 0.00,
            PSYS_SRC_BURST_SPEED_MAX, 0.00,
            PSYS_SRC_OMEGA, <0.00,0.00,0.00>,
            PSYS_SRC_TEXTURE, texture]);
    }
 
    if (TexturePrim)
    {
        llSetTexture(texture, ALL_SIDES);
    }
}
 
 
ShutDown()
{
    Power = FALSE;
    PowerText = "On";
    CloseAllListens();
    llSensorRemove();
    StopRotation();
    ProjectTexture();
    llOwnerSay("\nThe " + ObjectName + " is now switched OFF.");
}
 
 
StopRotation()
{
    llTargetOmega(<0.0,0.0,0.0>, 0.0, PI);
}
 
 
CloseAllListens()
{
    CloseUserListen();
    llListenRemove(OwnerListenChannel);
    OwnerListenText = "OpenListen";
}
 
 
CloseUserListen()
{
    llSetTimerEvent(0.0);
    llListenRemove(ListenChannel);
}
 
 
default
{
 
    on_rez(integer start_param)
    {
        // reset script on rez
        llResetScript();
    }
 
    changed( integer change )
    {
        if(change & CHANGED_OWNER )
        {
            // reset script on change of owner
            llResetScript();
        }
    }
 
    state_entry()
    {
        //initialise system
        InitialiseObject();
        SetFloatingText();
        ProjectTexture();
        AnnounceWelcome();
    }
 
    touch_start(integer total_number)
    {
        DetectedUser = llDetectedKey(0);
        list MenuItems = ["LearnMore", "GetScript", "Help"];
        string MenuText = "MAIN MENU: Please make a selection within " + (string)llFloor(DialogTimeout)
            + " seconds.\n- LearnMore: Read the forum thread on this product\n- GetScript: Get yourself the latest version of this free script\n- Help: Link to the "
            + ObjectName + " Help page";
 
        if (DetectedUser == ObjectOwner)
        {
            // touched by Owner
 
            if (Power)
            {
                MenuItems = [PowerText, OwnerListenText] + MenuItems;
                MenuText = MenuText + "\n- Off: Switch off \n- Open/CloseListen: Opens/Closes Owner listen channel " + (string)OwnerChannel;
            }
            else
            {
                MenuItems = (list)PowerText + MenuItems;
                MenuText = MenuText + "\n- On: Switch on";
            }
        }
        else
        {
            // touched by someone other than Owner. Send them a message & a dialog box of options
 
            // if they placed their own name on 'Exclude List', so give opportunity to clear their name, else give opportunity to exclude their name
            if (llListFindList(ExcludeListing, (list)(llKey2Name(AVKey) + SelfExcludedSuffix)) != -1 )
            {
                // they placed themself on the 'Exclude List' so are therefore allowed to clear their name
                MenuItems = (list)"IncludeMe" + MenuItems;
                MenuText =  MenuText + "\n- IncludeMe: Have the " + ObjectName + " remove your name from the 'Exclude List'";
            }
            else
            {
                // they have not placed themself on the 'Exclude List', so check whether the Owner has already done it
                if (llListFindList(ExcludeListing, (list)llKey2Name(AVKey)) == -1 )
                {
                    // neither they themself nor the Owner has previously excluded them, so give them the opportunity to exclude themselves now
                    MenuItems = (list)"ExcludeMe" + MenuItems;
                    MenuText =  MenuText + "\n- ExcludeMe: Have your name added to the " + ObjectName + "'s 'Exclude List'";
                }
            }
            llInstantMessage(DetectedUser, "\nThank you for your interest in the " + ObjectName + " created by " + Author + "\nThe dialog menu offers a number of options.");
        }
        // generate the dialog menu
        integer CommChannel = (-200000 - ((integer)llFrand(12345) * -1));
        ListenChannel = llListen(CommChannel, "", DetectedUser, "");
        llDialog(DetectedUser, MenuText, MenuItems, CommChannel);
        llSetTimerEvent(DialogTimeout);
    }
 
 
    sensor(integer total_number)
    {
        // save the AV key in case it is needed for a 'ShoutOut'
        AVKey = llDetectedKey((integer)llFrand(total_number));
        // core code by Coder Kas. Adapted to suit by Debbie Trilling
        string URL_RESIDENT = "http://world.secondlife.com/resident/";
        llHTTPRequest( URL_RESIDENT + (string)AVKey,[HTTP_METHOD,"GET"],"");
    }
 
 
    no_sensor()
    {
        // counts the number of times that the scanner doesn't find anyone in range. If TotalNoScansAllowed is set to greater than zero, automatically powers down the toy
        // when the number of no_sensors exceeds TotalNoScansAllowed. However, this functionality is disabled if TotalNoScansAllowed is set to zero.
        NoSensorCounter++;
        if ((NoSensorCounter > TotalNoScansAllowed) && (TotalNoScansAllowed > 0))
        {
            ShutDown();
            llInstantMessage(ObjectOwner, "\nThe " + ObjectName + " has been automatically switched OFF as no Agents have been detected within the set timeframe.");
        }
        else
        {
            ApplyDefaultTexture();
        }
    }
 
 
    http_response(key req,integer stat, list met, string body)
    {
        // core code by Coder Kas. Adapted to suit by Debbie Trilling
        integer s1 = llSubStringIndex(body, profile_key_prefix);
        integer s1l = profile_key_prefix_length;
        if(s1 == -1)
        { // second try with img tag
            s1 = llSubStringIndex(body, profile_img_prefix);
            s1l = profile_img_prefix_length;
        }

        if(s1 == -1)
        {
            // selected AV doesn't have a profile picture, so use the default instead
            ApplyDefaultTexture();
        }
        else
        {
            key NewTexture = (key)llGetSubString(body,s1+s1l,s1+s1l+35);
 
            //check whether this was the texture used last time
            if (NewTexture == LastTexture || NewTexture == NULL_KEY)
            {
                // same profile pic as last time. so display a random default instead
                ApplyDefaultTexture();
                // clear the last texture out
                LastTexture = "";
            }
            else
            {
                // are they on the ExcludeListing, with or without a suffix? if so, display a random default texture instead
                if ((llListFindList(ExcludeListing, (list)llKey2Name(AVKey)) != -1 ) || (llListFindList(ExcludeListing, (list)(llKey2Name(AVKey) + SelfExcludedSuffix)) != -1))
                {
                    // they are on the 'Exclude List'
                    ApplyDefaultTexture();
                }
                else
                {
                    // different profile from last time & not on ExcludeListing, so display it
                    ApplySelectedTexture(NewTexture);
                    // save the key for comparison purposes next time tho'
                    LastTexture = NewTexture;
 
                    // give a 'ShoutOut', if set to do so
                    if (ShoutOut)
                    {
                        GiveShoutOut();
                    }
                }
            }
        }
    }
 
 
    listen(integer channel, string name, key id, string message)
    {
 
        if (message == "LearnMore")
        {
            string URL_FORUMTHREAD = "http://forums-archive.secondlife.com/54/1b/225692/1.html";
            llLoadURL(DetectedUser, "Thank you for choosing to learn more about the " + ObjectName + ".This link will take you to the relevant SL forum thread.", URL_FORUMTHREAD);
            CloseUserListen();
        }
        else if (message == "GetScript")
        {
            string URL_WIKIPAGE = "http://wiki.secondlife.com/wiki/User:Debbie_Trilling";
            llLoadURL(DetectedUser, "Thank you for choosing to look at the script for the " + ObjectName + ".This link will allow you to get your own free copy.", URL_WIKIPAGE);
            CloseUserListen();
        }
        else if (message == "Help")
        {
            string URL_HELPPAGE = "http://wiki.secondlife.com/wiki/Talk:Random_AV_Profile_Projector";
            llLoadURL(DetectedUser, "This link will take you to the " + ObjectName + "'s Help page.", URL_HELPPAGE);
            CloseUserListen();
        }
        else if (message == "ExcludeMe")
        {
            // as a suffix to the name, as it is the user adding their own name
            ExcludeListing = (list)(llKey2Name(DetectedUser) + SelfExcludedSuffix) + llList2List( ExcludeListing, 0, (ExcludeListSize - 2));
            llInstantMessage(DetectedUser, "You have been added to the " + ObjectName + "'s 'Exclude List'");
            CloseUserListen();
        }
        else if (message == "IncludeMe")
        {
            integer ExcludeListPosition = llListFindList(ExcludeListing, (list)(llKey2Name(DetectedUser) + SelfExcludedSuffix));
            ExcludeListing = llDeleteSubList(ExcludeListing, ExcludeListPosition, ExcludeListPosition);
            llInstantMessage(DetectedUser, "You have been removed from the " + ObjectName + "'s 'Exclude List'");
            CloseUserListen();
        }
        else if ((message == "On") && (id == ObjectOwner))
        {
            StartUp();
        }
        else if ((message == "Off") && (id == ObjectOwner))
        {
            ShutDown();
        }
        else if ((message == "OpenListen") && (id == ObjectOwner))
        {
            // open the Owner Only channel
            OwnerListenChannel = llListen(OwnerChannel, "", ObjectOwner, "");
            OwnerListenText = "CloseListen";
            llOwnerSay("Owner Only channel " + (string)OwnerChannel + " is now open for you.\n Options are: 'Exclude <AV_NAME>', 'Include <AV_NAME>', 'ClearAll' and 'List'");
        }
        else if ((message == "CloseListen") && (id == ObjectOwner))
        {
            // close the Owner Only channel
            llListenRemove(OwnerListenChannel);
            OwnerListenText = "OpenListen";
            llOwnerSay("Owner Only channel " + (string)OwnerChannel + " is now closed.");
        }
        else if (((llGetSubString(message,0,6) == "Exclude") || (llGetSubString(message,0,6) == "exclude")) && (id == ObjectOwner))
        {
            // before adding them to the 'Exclude List', check if already on it
            // they could be on the list simply as their own name, their name + a suffix, perhaps even both.
 
            if ((DeriveNamePosition(message) != -1 ) || (DeriveNamePosition(message + SelfExcludedSuffix) != -1))
            {
                llOwnerSay(DeriveName(message) + " already exists on the " + ObjectName + "'s 'Exclude List'.");
            }
            else
            {
                // not on the list, so add them (without a suffix, as it is the Owner doing the adding)
                string NewExcludeName = DeriveName(message);
                ExcludeListing = (list)NewExcludeName + llList2List( ExcludeListing, 0, (ExcludeListSize - 2));
                llOwnerSay(NewExcludeName + " has been added to the "
                    + ObjectName + "'s 'Exclude List'. \nThere are now " + RemainingExcludeSlots());
            }
        }
        else if (((llGetSubString(message,0,6) == "Include") || (llGetSubString(message,0,6) == "include")) && (id == ObjectOwner))
        {
            // they could be on the list simply as their own name, their name + a suffix, perhaps even both. We need to test for all scenerios
            // locate their position within in 'Exclude List', if they do exist
            integer NamePositionTest = DeriveNamePosition(message);
            integer NamePositionSuffixTest = DeriveNamePosition(message + SelfExcludedSuffix);
 
            // test to see if either are on the 'Exclude List'.
            if ((NamePositionTest != -1) || (NamePositionSuffixTest != -1))
            {
                // well, their name is definately on the 'Exclude list', but is it with or without a suffix? Is it both?
                // would look neater to do the next tests in an IF-IF/ELSE-ELSE, but we can save a lil memory using two IF statement (albeit with a tiny speed overhead)
                if (NamePositionTest != -1)
                {
                    // it's on without a suffix
                    ExcludeListing = llDeleteSubList(ExcludeListing, NamePositionTest, NamePositionTest);
                }
 
                if (NamePositionSuffixTest != -1)
                {
                    //it's on with a suffix
                    ExcludeListing = llDeleteSubList(ExcludeListing, NamePositionSuffixTest, NamePositionSuffixTest);
                }
                llOwnerSay(DeriveName(message) + " has been removed from the "
                    + ObjectName + "'s 'Exclude List'. \nThere are now " + RemainingExcludeSlots());
            }
            else
            {
                llOwnerSay(DeriveName(message) + " could not located on the " + ObjectName + "'s 'Exclude List'.");
            }
        }
        else if (((llGetSubString(message,0,7) == "ClearAll") || (llGetSubString(message,0,7) == "clearall") || (llGetSubString(message,0,8) == "clear all") || (llGetSubString(message,0,8) == "Clear all")) && (id == ObjectOwner))
        {
            ExcludeListing = [];
            llOwnerSay("The 'Exclude List' has been cleared. All " + RemainingExcludeSlots());
 
        }
        else if (((llGetSubString(message,0,3) == "List") || (llGetSubString(message,0,3) == "list")) && (id == ObjectOwner))
        {
            if (llGetListLength(ExcludeListing) > 0)
            {
                llOwnerSay("The following " + (string)llGetListLength(ExcludeListing) + " AV's are listed on the 'Exclude List'. Names ending with '" + SelfExcludedSuffix + "' chose to exclude themselves.\n"
                    + llDumpList2String(ExcludeListing, " | "));
            }
            else
            {
                llOwnerSay("No AV's are listed on the 'Exclude List'.");
            }
        }
        else
        {
            llInstantMessage(DetectedUser, "Unrecognised option or selection made from a timed-out menu.");
        }
 
    }
 
    timer()
    {
        CloseUserListen();
    }
 
//default end
}