Visit Monitor

====Visit Monitor====
--BETLOG Hax UTC+10: 20090715 1159 [SLT: 20090714 1859]
Volumedetect (collision based) prim that records avatars names, number of visits, and time (in UTC)
 
Written in response to Firery Broome's request to "just add a few simple things" ...Resulting, as usual :) in an almost total rewrite, and functional differences to the original.
Re-posting here as S.A.3.0 licence to re-assert its original public status and that of my rewrite.
Not comprehensively tested, so may have some stupid in it.
TO USE:
ADD YOUR EMAIL ADDRESS TO THE GLOBAL VARIABLES
Put script in a prim, it'll be phantom from then on so don't link it to anything thats not going to be part of the collision sensing prim(s)
Any avatars colliding with this prim will have their name added to the visitor list.
Best placement is in avatar arrival areas, like forced TP parcels, preferably where avs will not be constantly colliding with the prim, but rather only collide once when they arrive in your sim/parcel.
If the script's memory becomes too full due to list size it will attempt to dump list to email and reset... but I havent't tested if 512bytes is even enough to do this successfully... so value may need adjustment.
//==============================================================
//Original script by Aaron Linden
//
//modified and commented by Ramon Kothari 
//
// Almost totally rewritten by BETLOG Hax
// UTC+10: 20090713 2306 [SLT: 20090713 0606]
// To remove silly guff and reformat (sheesh WHITESPACE people!), added some more useful stuff.
// For Firery Broome
//----------------------------------
// **** LICENCE START ****
// http://creativecommons.org/licenses/by-sa/3.0/
// Attribution licence:
// You must:
// -Include this unaltered licence information.
// -Supply my original script with your modified version.
// -Retain the original scripts' SL permissions. [+c/+m/+t]
// Or:
// -Link to the wiki URL from which you copied this script.
// -Document: "Uses parts of <scriptname> by BETLOG Hax"
// **** LICENCE END ****
//----------------------------------
//=========================================================================
// ------ CONFIGURATION ------
string gEmail = "";//************** ADD YOUR EMAIL ADDRESS HERE ****************
float gFreq = 604800.0;//60*60*24*7=604800 - 1 WEEK
// ------ CORE CODE ------
list gList = [];
//----------------------------------
f_sayHelp()
{ llOwnerSay( "This object records the names of everyone who collides with it." );
 llOwnerSay( "Commands the owner can say:" );
 llOwnerSay( "'help' - Shows these instructions." );
 llOwnerSay( "'say list' - Says the names of all visitors on the list.");
 llOwnerSay( "'reset list' OR 'email list' - Emails the names on the list and resets." );
}
//----------------------------------
f_output(integer mail)
{ string text;
 integer length;
 integer i = (gList!=[])-1;
 if(i<2)
 llOwnerSay("No data");
 else
 { string s = llGetObjectName();
 llSetObjectName(" ");
 while(i>-1)
 { text += "Name: "+llList2String(gList, i-2)+"\t"+
 " Visit: "+(string)llList2Integer(gList, i-1)+"\t"+
 " Last :"+llList2String(gList, i)+"[UTC]\n";
 length = llStringLength(text);
 if(mail && length>=3500)//partial send to avoid email overflow
 { if(0<llSubStringIndex(gEmail,"@"))
 { llEmail(gEmail, llGetRegionName()+" Visitor List "+(string)llGetTimestamp(), text);
 text="";
 }
 }
 else if (!mail && length>=240)//partial send to avoid text chat overflow
 { llOwnerSay(text);
 text="";
 }
 i-=3;
 }
 if(mail)//normal output
 { if(0<llSubStringIndex(gEmail,"@"))
 llEmail(gEmail, llGetRegionName()+" Visitor List 1/1 "+(string)llGetTimestamp(), text);
 }
 else
 llOwnerSay(text);
 }
}
//----------------------------------
default
{ on_rez(integer param) 
 { llSay(0, "Visitor List Maker started...");
 f_sayHelp();
 llResetScript();
 }
 state_entry() 
 { if(llGetFreeMemory()<17000)
 llOwnerSay("RECOMPILE THIS IN MONO. (it'll still work otherwise, just not as well.)");
 llVolumeDetect(TRUE);
 llListen(0, "", llGetOwner(), "");
 llOwnerSay("OK Running.");
 llSetTimerEvent(gFreq); 
 }
 timer()
 { llSetTimerEvent(0.0);
 f_output(1);
 llResetScript();
 } 
 touch_start( integer num)
 { if (llDetectedKey(num)==llGetOwner())
 f_sayHelp();
 }
 collision_start(integer num) 
 { string detected_name;
 integer index;
 string segment;
 integer start;
 integer visits; 
 do
 { --num;
 if(llDetectedType(num)&AGENT
 && llDetectedKey(num)!=llGetOwner()//rem out to test on yourself
 )
 { detected_name = llDetectedName(num);
 if(llGetFreeMemory()<512)
 llSetTimerEvent(0.1);
 else
 { index = llListFindList(gList, [detected_name]);
 if(-1==index)
 { gList += [detected_name]+[1]+[llGetTimestamp()];
//llOwnerSay("Adding new visitor: \n"+llList2CSV(gList));
 }
 else
 { gList = llListReplaceList(gList, [detected_name]+[llList2Integer(gList, index+1)+1]+[llGetTimestamp()], index, index+2);
//llOwnerSay("Updating visits: \n"+llList2CSV(gList)); 
 }
 }
 }
 
 } while(num>-1);
 }
 listen( integer channel, string name, key id, string message )
 { if( message == "help" )
 { f_sayHelp();
 }
 else if( message == "say list" || message == "output list" )
 { f_output(0);
 }
 else if( message == "email list" || message == "reset list" || message == "send email" )
 { llOwnerSay( "Sending email (incurs a 20 second delay) and resetting...");
 f_output(1);
 llResetScript();
 }
 } 
}
//=========================================================================
The original script.
//=========================================================================
//Original script by Aaron Linden
//modified and commented by Ramon Kothari 
// Global variables change these to match your specifics
float range = 10.0; // search radius, in meters
float rate = 1.0; // time between searches, in seconds
// add your email adress inside the quotes
string email_address = "";
//add the name of the location if you want (the email will have the sim name and cordinates of 
// the counter already in it) 
string location_name = "Your Location";
//dont change these 
list single_name_list;
list visitor_list;
//end no change
// Returns true if "name" is already on the visitor_list and doesnt add it the list again 
integer isNameOnList( string name )
{
list single_name_list;
single_name_list += name;
return (-1 != llListFindList( visitor_list, single_name_list ) );
}
// sends email to the address above ,if added 
sendEmail()
{
string csv = llList2CSV( visitor_list );
llEmail( email_address, "Visitor List: " + location_name, csv );
}
//self explanatory 
resetList()
{
single_name_list = llDeleteSubList(single_name_list, 0, llGetListLength(single_name_list));
llSay( 0, "Done resetting.");
}
// Help commands
sayHelp( integer is_owner )
{
if( is_owner )
{
llSay( 0, "This object records the names of everyone who" );
llSay( 0, "comes within "+ (string)((integer)range) + " meters." );
llSay( 0, "Commands the owner can say:" );
llSay( 0, "'help' - Shows these instructions." );
llSay( 0, "'say list' - Says the names of all visitors on the list.");
llSay( 0, "'reset list' - Removes all the names from the list." );
llSay( 0, "' email list' - Emails the names on the list." );
}
else
{
llSay( 0, "Sorry, only the owner can use this object." );
}
}
// state the script starts in 
default
{
state_entry()
{
llSay(0, "Visitor List Maker started...");
llSay(0, "The owner can say 'help' for instructions.");
llSensorRepeat( "", "", AGENT, range, TWO_PI, rate );
llListen(0, "", llGetOwner(), "");
//change this to how often you want the script to email the visitor list to you (or comment it out if you dont want the email .... by default its set to email you every hr then reset itself
llSetTimerEvent( 60 * 60 );
}
// Sends email and resets list as set in the settimerevent above
timer()
{
sendEmail();
resetList();
} 
//says help if owner clicks on it 
touch_start( integer num_detected )
{
integer i;
for( i = 0; i < num_detected; i++ )
{
sayHelp( llDetectedKey(i) == llGetOwner() );
}
}
//detects avatars and keeps time 
sensor( integer number_detected )
{
integer i;
for( i = 0; i < number_detected; i++ )
{
// Don't ever add the owner to the list.
if( llDetectedKey( i ) != llGetOwner() )
{
string detected_name = llDetectedName( i );
if( isNameOnList( detected_name ) == FALSE )
{
float seconds = llGetWallclock();
float minutes = seconds / 60.0;
float hours = minutes / 60.0;
integer hours_int = (integer) hours;
integer minutes_int = ((integer)minutes) % 60;
if( minutes_int < 10 )
{
visitor_list += (string) hours_int + ":0" + (string) minutes_int;
}
else
{
visitor_list += (string) hours_int + ":" + (string) minutes_int;
}
visitor_list += detected_name;
}
}
} 
}
//Listens for commands from the Owner
listen( integer channel, string name, key id, string message )
{
if( id != llGetOwner() )
{
return;
}
if( message == "help" )
{
sayHelp( TRUE );
}
else
if( message == "say list" )
{
llSay( 0, "Visitor List:" );
integer len = llGetListLength( visitor_list );
integer i;
for( i = 0; i < len; i++ )
{
llSay( 0, llList2String(visitor_list, i) );
}
llSay( 0, "Total = " + (string)len ); 
}
else
if( message == "email list" )
{
sendEmail();
llSay(0, "Emailing list");
}
else
if( message == "reset list" )
{
visitor_list = llDeleteSubList(visitor_list, 0, llGetListLength(visitor_list));
llSay( 0, "Done resetting.");
}
} 
}
//=========================================================================
Category:LSL Examples