Difference between revisions of "Random AV Profile Projector"
(WEB-1383 workaround) |
|||
Line 10: | Line 10: | ||
<lsl> | <lsl> | ||
// ~ RANDOM PROFILE PROJECTOR v5.4.5 by Debbie Trilling ~ | // ~ RANDOM PROFILE PROJECTOR v5.4.5 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 | ||
// profile picture as texture on a prim and/or a 'holographic' image projected above the prim*** | // 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, | // 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 | // and that due credit continues to be given to Moriash Moreau, Coder Kas and | ||
// Debbie Trilling. | // Debbie Trilling. | ||
// 2009-11-24 Viktoria Dovgal - mod to use <meta> tag, to work around WEB-1383 | |||
// 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 | // ONLINE HELP AT: http://wiki.secondlife.com/wiki/Talk:Random_AV_Profile_Projector | ||
// ** PARAMETERS THAT YOU CAN CHANGE ** | // ** PARAMETERS THAT YOU CAN CHANGE ** | ||
//************************ | //************************ | ||
// GENERAL PARAMETERS | // GENERAL PARAMETERS | ||
//************************ | //************************ | ||
// listen channel for Owner | // listen channel for Owner | ||
integer OwnerChannel = 54321; | integer OwnerChannel = 54321; | ||
// set the maximum number of entries in the 'Exclude List' at any one time | // set the maximum number of entries in the 'Exclude List' at any one time | ||
integer ExcludeListSize = 30; | integer ExcludeListSize = 30; | ||
// the number of seconds that a listen remains open before timing-out & automatically closing | // the number of seconds that a listen remains open before timing-out & automatically closing | ||
float DialogTimeout = 20.00; | 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; | ||
// sensor range in meters. Maximum 96m but in practice 10 to 30m because of particle draw distance | // sensor range in meters. Maximum 96m but in practice 10 to 30m because of particle draw distance | ||
float Range = 25.00; | float Range = 25.00; | ||
// sets the number of consecutive times that the scanner is allowed to operate without having located an AV within range | // 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 | // 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 | // anyone before it automatically powers down. Set to '0' to disable the auto-off function | ||
integer TotalNoScansAllowed = 20; | integer TotalNoScansAllowed = 20; | ||
// texture palette of UUID's. One will be randomly selected for display when an AV without a profile pic is selected | // 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"]; | 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 | // 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; | integer EmployDefaultTexture = TRUE; | ||
// What we look for in world.secondlife.com to find the image UUID | |||
string profile_key_prefix = "<meta name=\"imageid\" content=\""; | |||
// length of profile_key_prefix, filled in at InitialiseObject() | |||
integer s1l; | |||
//************************ | //************************ | ||
// 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; | ||
// width size in meters of the projected image (max 4.00) | // width size in meters of the projected image (max 4.00) | ||
float Size = 2.50; | 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)) | // 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; | float Height = 2.50; | ||
//************************ | //************************ | ||
// 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 ("EmployDefaultTexture = FALSE") OR ("EmployDefaultTexture = TRUE" and "TexturePrim=FALSE") | // 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 | // 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 PrimUUIDTexture = "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 | ||
integer PrimFullBright = FALSE; | integer PrimFullBright = FALSE; | ||
// vector for the prim colour when toy is OFF | // vector for the prim colour when toy is OFF | ||
vector PrimColour = <0.0, 0.0, 0.0>; | 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 | // 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 | // set the degree of 'shininess' to apply to the prim "0" = None, "1" = Low, "2" = medium, "3" = high | ||
integer PrimShine = 3; | integer PrimShine = 3; | ||
//************************ | //************************ | ||
// FLOATING TEXT PARAMETERS | // FLOATING TEXT PARAMETERS | ||
Line 101: | Line 108: | ||
// set to TRUE for floating text above the prim; FALSE to disable the floating text | // set to TRUE for floating text above the prim; FALSE to disable the floating text | ||
integer ApplyFloatingText = TRUE; | integer ApplyFloatingText = TRUE; | ||
// set the text to be displayed | // set the text to be displayed | ||
string FloatingText = "'Touch' for more information"; | string FloatingText = "'Touch' for more information"; | ||
// set the text colour | // set the text colour | ||
vector FloatingTextColour = <1.0,1.0,0.0>; | vector FloatingTextColour = <1.0,1.0,0.0>; | ||
// set the text alpha | // set the text alpha | ||
float FloatingTextAlpha = 0.8; | float FloatingTextAlpha = 0.8; | ||
//************************ | //************************ | ||
// ROTATION PARAMETERS | // ROTATION PARAMETERS | ||
//************************ | //************************ | ||
// if TRUE, applies a slow rotation to the prim when the toy is swtiched ON and TexturePrim = TRUE; FALSE to disable rotation | // 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; | integer ApplyRotation = FALSE; | ||
//************************ | //************************ | ||
// 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; | ||
// 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!" | // 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!"; | string ShoutOutText = "'s face is up in lights!"; | ||
//************************ | //************************ | ||
// ** DO NOT CHANGE BELOW THIS LINE ** | // ** DO NOT CHANGE BELOW THIS LINE ** | ||
//************************ | //************************ | ||
integer Power = FALSE; | integer Power = FALSE; | ||
integer ListenChannel; | integer ListenChannel; | ||
Line 152: | Line 159: | ||
string Author = "Debbie Trilling"; | string Author = "Debbie Trilling"; | ||
string Supplier = "The Particle Crucible"; | string Supplier = "The Particle Crucible"; | ||
string Version = " v5.4.5"; | string Version = " v5.4.5.20091124"; | ||
string OwnerListenText = "OpenListen"; | string OwnerListenText = "OpenListen"; | ||
string SelfExcludedSuffix = "**"; | string SelfExcludedSuffix = "**"; | ||
string PowerText = "On"; | string PowerText = "On"; | ||
list ExcludeListing = []; | list ExcludeListing = []; | ||
GiveShoutOut() | 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() | 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() | InitialiseObject() | ||
{ | { | ||
llParticleSystem([]); | |||
StopRotation(); | |||
ObjectOwner = llGetOwner(); | |||
OwnerName = llKey2Name(ObjectOwner); | |||
llSetObjectName(ObjectName + Version); | |||
llSetObjectDesc("Supplied free by " + Author + "'s " + Supplier); | |||
CloseAllListens(); | |||
s1l = llStringLength(profile_key_prefix); | |||
} | } | ||
SetFloatingText() | SetFloatingText() | ||
{ | { | ||
if (ApplyFloatingText) | |||
{ | |||
llSetText(FloatingText, FloatingTextColour, FloatingTextAlpha); | |||
} | |||
else | |||
{ | |||
llSetText("",<1.0,1.0,1.0>,0.0); | |||
} | |||
} | } | ||
ProjectTexture() | 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() | 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, | |||
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() | 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() | ApplyPrimUpdate() | ||
{ | { | ||
if (TexturePrim) | |||
{ | |||
ApplyPrimSurface(); | |||
if (ApplyRotation) | |||
{ | |||
llTargetOmega(<0.0,0.0,1.0>, 0.2, PI); | |||
} | |||
} | |||
} | } | ||
ApplyDefaultTexture() | ApplyDefaultTexture() | ||
{ | { | ||
ApplySelectedTexture((key)llList2String(DefaultTexturePalette, (integer)llFrand((float)llGetListLength(DefaultTexturePalette)))); | |||
} | } | ||
string RemainingExcludeSlots() | string RemainingExcludeSlots() | ||
{ | { | ||
string RemainingSlots = (string)(ExcludeListSize - llGetListLength(ExcludeListing)) + " slots are now available."; | |||
return RemainingSlots; | |||
} | } | ||
string DeriveName(string messagecapture) | string DeriveName(string messagecapture) | ||
{ | { | ||
string DerivedName = llGetSubString(llStringTrim(messagecapture,STRING_TRIM),8,llStringLength(llStringTrim(messagecapture,STRING_TRIM))); | |||
return DerivedName; | |||
} | } | ||
integer DeriveNamePosition(string messagecapture) | 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) | 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() | ShutDown() | ||
{ | { | ||
Power = FALSE; | |||
PowerText = "On"; | |||
CloseAllListens(); | |||
llSensorRemove(); | |||
StopRotation(); | |||
ProjectTexture(); | |||
llOwnerSay("\nThe " + ObjectName + " is now switched OFF."); | |||
} | } | ||
StopRotation() | StopRotation() | ||
{ | { | ||
llTargetOmega(<0.0,0.0,0.0>, 0.0, PI); | |||
} | } | ||
CloseAllListens() | CloseAllListens() | ||
{ | { | ||
CloseUserListen(); | |||
llListenRemove(OwnerListenChannel); | |||
OwnerListenText = "OpenListen"; | |||
} | } | ||
CloseUserListen() | CloseUserListen() | ||
{ | { | ||
llSetTimerEvent(0.0); | |||
llListenRemove(ListenChannel); | |||
} | } | ||
default | 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); | |||
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) | |||
{ | |||
// 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.secondlife.com/showthread.php?t=225692"; | |||
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 | //default end | ||
} | } | ||
</lsl> | </lsl> |
Revision as of 04:41, 24 November 2009
LSL Portal | Functions | Events | Types | Operators | Constants | Flow Control | Script Library | Categorized Library | Tutorials |
~ 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
<lsl>
// ~ RANDOM PROFILE PROJECTOR v5.4.5 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 Viktoria Dovgal - mod to use <meta> tag, to work around WEB-1383
// 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;
// What we look for in world.secondlife.com to find the image UUID string profile_key_prefix = "<meta name=\"imageid\" content=\"";
// length of profile_key_prefix, filled in at InitialiseObject() integer s1l;
//************************ // 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.20091124";
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(); s1l = llStringLength(profile_key_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); 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) { // 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.secondlife.com/showthread.php?t=225692"; 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 } </lsl>