Visitor Counter and Landmark Giver

Written by: Headmaster
// Simple visitor counter and lm giver script.
//
// Can also run as a simple 'add me to the waiting list' script
// too (i.e. remembers everyone who touches the object).
//
// Just finds the first landmark stored in the prim and
// gives it to non-owners on touch.
//
// For owners, if the prim is touched, presents a simple
// dialog to either list visitors or reset the visitors counts.
//
// Kimm Paulino
// Written for Vikki Hastings, Oct 2010
// Updated for waiting list, Mar 2012
 
// Configure the behaviour we want
integer gWaitingList = FALSE;      // enable waiting list only functionality
integer gLogDates = TRUE;        // Include timestamps in the log
integer gJustDates = FALSE;		 // But only dates (not timestamps)
integer gKeepFirst = FALSE;        // Keep the first visit of someone, not the last
string  gFloatingText = "";  // Set to "" to disable
vector  gFloatingTextColour = <1.0, 1.0, 1.0>;
float   gFloatingTextAlpha = 1.0;
float   gSensorRange = 15.0;
 
integer MAX_VISITORS = 30;
list gVisitors;
list gVisitorTimes;
integer gVisitorCount;
integer gChannel;
integer gListenHandle;
 
integer getRandomChannel()
{
    // Some magic I got of the SL wiki somewhere ...
    return -llRound(llFrand( llFabs(llSin(llGetGMTclock())) * 1000000 )) - 11;
}
 
listVisitors ()
{
    llOwnerSay("----------------");
    llOwnerSay("Total number of visits: " + (string)gVisitorCount);
    if (gVisitorCount > 0)
    {
        llOwnerSay("Most recent visitors:");
        integer i;
        integer len = llGetListLength(gVisitors);
        for (i=0; i < len; i++)
        {
            if (gLogDates)
            {
                llOwnerSay("[" + llList2String (gVisitorTimes, i) + "] " +llList2String(gVisitors,i));
            }
            else
            {
                llOwnerSay(llList2String(gVisitors,i));
            }
        }
    }
}
 
resetVisitors()
{
    llOwnerSay ("Resetting visitor count");
    gVisitors = [];
    gVisitorTimes = [];
    gVisitorCount = 0;
}
 
addVisitor(string name)
{
    // see if we've already seen this one
    integer idx = llListFindList(gVisitors, (list)name);
    if (idx != -1 )
    {
        // Already in the list, so:
        // If storing dates, then need to decide if we are keeping
        // the first visit or the last
        //
        // If we are not keeping dates, just don't bother logging again
        if (!gLogDates)
        {
            return;
        }
 
        if (gKeepFirst)
        {
            // Already have the entry we wish to keep ...
            return;
        }
 
        // ok, we are keeping the last visits, so remove
        // the name from the list and let the rest of the function
        // add it in again!
        gVisitors = llDeleteSubList (gVisitors, idx, idx);
        gVisitorTimes = llDeleteSubList (gVisitorTimes, idx, idx);
    }
    else
    {
        // Note:  Will count people who visited before but have
        // now dropped off the end of the 'last visitors' list, but
        // thats all.
        gVisitorCount ++;
    }
 
    //llOwnerSay ("Adding " + name);
    gVisitors += name;
	if (gJustDates)
	{
		gVisitorTimes += llGetDate();
	}
	else
	{
        list timestamp = llParseString2List(llGetTimestamp(),["T","."],[""]);
		string time = llList2String(timestamp, 0) + " " + llList2String(timestamp, 1);
		gVisitorTimes += time;
	}
 
    // See if we are at the end of the list
    // this helps to keep memory limits down
    // and also creates a rolling list of most
    // recently seen avs
    if (llGetListLength(gVisitors) > MAX_VISITORS)
    {
        // Remove first entry in the list
        gVisitors = llDeleteSubList (gVisitors, 0, 0);
        gVisitorTimes = llDeleteSubList (gVisitorTimes, 0, 0);
    }
}
 
default
{
    on_rez (integer start_param)
    {
        llResetScript();
    }
 
    state_entry()
    {
        resetVisitors();
        gChannel = getRandomChannel();
 
        llSetText (gFloatingText, gFloatingTextColour, gFloatingTextAlpha); 
 
        if (!gWaitingList)
        {
            // Range, angle, rate
            // So 5m range, 180 deg, every 5 secs
            llSensorRepeat ("", NULL_KEY, AGENT, gSensorRange, PI, 5.0);
        }
    }
 
    sensor(integer total_number)
    {
        integer i;
        //llSay (0, "Found " + (string)total_number);
        for (i=0 ; i