Table of Contents

ChangeLog

20 July 2014

  • Code maintenance.

7 March 2013

  • Removed the visitors feature since it was redundant. For a more complete visitors solution, choose one of the visitors scripts and run them separately.
  • Script maintenance.

30 August 2011

  • Group invite added on request for Tray Guisse.

About

This is a standard visitor greeter, compatible with the mail system, which has the following features:

  • Sending an instant message whenever a new visitor is detected.
  • Handing out a landmark, a notecard and a gift.
  • Letting visitors subscribe (compatible with the mail system).
  • Sending an URL.
  • Keeping statistics of the number of requested items from the greeter.
  • Access list for shared management of the greeter.

Setup

In order to make this greeter work, you would have to place it somewhere close to the landing point so that new visitors get scanned more efficiently. To set it up, first create a notecard called Access containing the avatar names of administrators line-by-line. For example, if avatar Morgan LeFay and avatar Frank Black should both be able to manage the greeter, the notecard would look like this:

Morgan LeFay
Frank Black

You can add as many administrators as you like to the notecard. Next, configure the script so that it matches your liking. The section in the script that you should change is the one marked with the CONFIGURATION comment:

///////////////////// CONFIGURATION //////////////////
string GREET_MESSAGE = "Hello!";
string DIALOG_MESSAGE = "Welcome, please select from the options below: ";
string SUBSCRIBE_MESSAGE = "Thank you for subscribing! We will keep you updated!";
integer SCAN_RANGE = 10;
integer SCAN_INTERVAL = 2;
string URL = "http://wiki.secondlife.com/wiki/Greeter";
list USER_OPTIONS = ["Landmark", "Subscribe", "URL", "Notecard", "Gift"];
key INVITE_GROUP_KEY = "9092e77a-ed89-508d-30a9-456873423901";
string INVITE_GROUP_MESSAGE = "To join the group, please click the link in your history window (ctrl+h):";
/////////////////////////////////////////////////////
  • The GREET_MESSAGE is the message that your visitors will get once they are scanned. You can change it from the factory default "Hello!" to anything else. For example, you could change it to:
string GREET_MESSAGE = "Hello and welcome to The Chocolate Factory! Please enjoy our cocoa...";
  • The DIALOG_MESSAGE is what the visitors will see in the dialog description, which will pop up on their screen. Usually this is used to describe the options on the buttons, however, just like the GREET_MESSAGE you may change to anything that suits you.
  • The SUBSCRIBE_MESSAGE is the message that the greeter will send after a visitor has subscribed. You can change this of course to your liking.
  • The SCAN_RANGE is the range in meters that the greeter will scan for new visitors. The factory default is 10 meters and it can go up to 96 meters. To change this, for example to make the scanning range 30 meters, one would modify the line like this:
string SCAN_RANGE = 30;
  • The SCAN_INTERVAL, similar to the SCAN_RANGE is the frequency with which the greeter will scan for new visitors. The factory default is to scan every two seconds and you can change this as you like.
  • The URL is an optional URL or message that can be sent to a visitor once they press the "URL" button. The factor default is just a link to this article.
  • The USER_OPTIONS is the main feature control of the greeter. It is a list consisting of options provided to the visitors when they get scanned by the greeter. By modifying this line, you can change what the greeter will provide to the visitors. For example, the factory default has all the options turned on:
list USER_OPTIONS = ["Landmark", "Subscribe", "URL", "Notecard", "Group", "Gift"];

This means that the greeter will offer landmarks, offer subscriptions, offer to send URLs, offer to send a notecard and offer to send a gift. However, you might not want to send gifts, for example. In that case, you can disable the gift sending feature by simply modifying this line. For example, to disable the gift sending option, you would change this line to:

list USER_OPTIONS = ["Landmark", "Subscribe", "URL", "Notecard", "Group" ];
  • The INVITE_GROUP_KEY is the key to a group you would want the greeter to invite you to.
  • The INVITE_GROUP_MESSAGE is the message that will be sent to the user before they are invited to the group. It also contains the group link they will have to click in order to get the group information and be able to join.

The final step is to add a landmark, a notecard and perhaps a gift to the prim containing the greeter. When a visitor clicks an option, say "Landmark", the greeter will hand out the first landmark in the prim. The same applies, to notecards and gifts (objects). The greeter does not support sending multiple objects, however you can always bundle a bunch of stuff in an object and send it as a gift.

To connect the greeter with the mail system, an administrator on the access list would have to select Dump Subs. This will make the greeter list all subscribers line by line in the mail system's Subscriber notecard format. For example, from time to time after users have subscribed using the greeter, an administrator would have to click the greeter and select Dump Subs, this will subscribers line-by-line:

1ad33407-a792-476d-a5e3-06007c0802bf#Morgan LeFay
82c73d6d-facf-4332-b17b-06d8cd66a116#Frank Black

The administrator will copy these lines and paste them into the mail system Subscriber notecard in order to make the mail system work.

Hacks

  • One hack you can do is to change the buttons. For example, instead of "Notecard" you would want to have something like "Rules". In order to make this example change, you have to modify:
list USER_OPTIONS = ["Landmark", "Subscribe", "URL", "Notecard", "Gift", "Group"];

to:

list USER_OPTIONS = ["Landmark", "Subscribe", "URL", "Rules", "Gift", "Group"];

as well as change the line:

if(message == "Notecard") {

to:

if(message == "Rules") {

and proceed the same with every button you wish to change.

Code

This script was tested and works on OpenSim version 0.7.4!

greeter.lsl
///////////////////////////////////////////////////////////////////////////
//  Copyright (C) Wizardry and Steamworks 2011 - License: GNU GPLv3      //
//  Please see: http://www.gnu.org/licenses/gpl.html for legal details,  //
//  rights of fair usage, the disclaimer and warranty conditions.        //
///////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
//                            CONFIGURATION                              //
///////////////////////////////////////////////////////////////////////////
 
string GREET_MESSAGE = "Hello!";
string DIALOG_MESSAGE = "Welcome, please select from the options below: ";
string SUBSCRIBE_MESSAGE = "Thank you for subscribing! We will keep you updated!";
string SUBSCRIBE_ALREADY_SUBSCRIBED = "Thank you, you are already subscribed.";
integer SCAN_RANGE = 10;
integer SCAN_INTERVAL = 2;
string URL = "http://grimore.org/secondlife:greeter";
list USER_OPTIONS = ["Landmark", "Subscribe", "URL", "Notecard", "Gift", "Group"];
key INVITE_GROUP_KEY = "9092e87a-ed89-509d-30a9-456873423901";
string INVITE_GROUP_MESSAGE = "To join the group, please click the link in your history window (ctrl+h):";
 
///////////////////////////////////////////////////////////////////////////
//                              INTERNALS                                //
///////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueGet(string k, string data) {
    if (llStringLength(data) == 0) return "";
    if (llStringLength(k) == 0) return "";
    list a = llParseStringKeepNulls(data, ["&", "="], []);
    integer i = llListFindList(a, [ k ]);
    if (i != -1) return llList2String(a, i + 1);
    return "";
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueSet(string k, string v, string data) {
    if (llStringLength(data) == 0) return k + "=" + v;
    if (llStringLength(k) == 0) return "";
    if (llStringLength(v) == 0) return "";
    integer i = llListFindList(
        llList2ListStrided(
            llParseString2List(data, ["&", "="], []),
            0, -1, 2
            ),
        [ k ]);
    if (i != -1) return llDumpList2String(
            llListReplaceList(
                llParseString2List(data, ["&"], []),
                [ k + "=" + v ],
                i, i),
            "&");
    return data + "&" + k + "=" + v;
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueDelete(string k, string data) {
    if(llStringLength(data) == 0) return "";
    if(llStringLength(k) == 0) return "";
    integer i = llListFindList(
        llList2ListStrided(
            llParseString2List(data, ["&", "="], []), 
            0, -1, 2
        ), 
    [ k ]);
    if(i != -1) return llDumpList2String(
        llDeleteSubList(
            llParseString2List(data, ["&"], []),
        i, i), 
    "&");
    return data;
}
 
list aList = [];
list kList = [];
list sList = [];
 
list dialogs = [];
integer line = 0;
 
default {
    state_entry() {
        if (llGetInventoryType("Access") != INVENTORY_NOTECARD) {
            llSay(DEBUG_CHANNEL, "Unable to a notecard named Access.");
            return;
        }
        aList = [];
        llGetNotecardLine("Access", line);
    }
 
    dataserver(key query_id, string data) {
        if (data == EOF) state scan;
        if (data == "") jump continue;
        aList += (list)data;
@continue;
        llGetNotecardLine("Access", ++line);
    }
 
    changed(integer change) {
        if (change & CHANGED_INVENTORY) llResetScript();
    }
}
 
state scan {
    state_entry() {
        llSensorRepeat("", "", AGENT, SCAN_RANGE, PI, SCAN_INTERVAL);
    }
 
    timer() {
        integer handles = llGetListLength(dialogs) - 1;
        do {
            llListenRemove(llList2Integer(dialogs, handles));
        } while (--handles > -1);
    }
 
    touch_start(integer num) {
        key agent = llDetectedKey(0);
        integer channel = (integer)("0x8" + llGetSubString(llGetKey(), 0, 6));
        integer com = llListen(channel, "", agent, "");
        if (llListFindList(dialogs, (list)com) == -1) dialogs += com;
        if (llListFindList(aList, (list)llDetectedName(0)) != -1) {
            llDialog(agent, "Welcome to the greeter control, please choose your configuration options: \n", [ "Visitors", "Dump Subs", "Statistics", "Full Reset" ], channel);
            jump time;
        }
        llDialog(agent, DIALOG_MESSAGE, USER_OPTIONS, channel);
@time;
        llSetTimerEvent(60);
    }
 
    listen(integer channel, string name, key id, string message) {
        if (message == "Group") {
            llInstantMessage(id, INVITE_GROUP_MESSAGE + "\n secondlife:///app/group/" + (string)INVITE_GROUP_KEY + "/about");
            jump menu;
        }
        if (message == "Landmark") {
            if (llGetInventoryNumber(INVENTORY_LANDMARK) == 0) {
                llInstantMessage(id, "Sorry, no landmark is available at this time.");
                jump menu;
            }
            llGiveInventory(id, llGetInventoryName(INVENTORY_LANDMARK, 0));
            llSetObjectDesc(
                wasKeyValueSet(
                    "landmarks",
                    (string)(
                        (integer)(
                            wasKeyValueGet("landmarks", llGetObjectDesc())
                            ) + 1
                        ),
                    llGetObjectDesc()
                    )
                );
            jump menu;
        }
        if (message == "Gift") {
            if (llGetInventoryNumber(INVENTORY_OBJECT) == 0) {
                llInstantMessage(id, "Sorry, no gift is available at this time.");
                jump menu;
            }
            llGiveInventory(id, llGetInventoryName(INVENTORY_OBJECT, 0));
            llSetObjectDesc(
                wasKeyValueSet(
                    "gifts",
                    (string)(
                        (integer)(
                            wasKeyValueGet("gifts", llGetObjectDesc())
                            ) + 1
                        ),
                    llGetObjectDesc()
                    )
                );
            jump menu;
        }
        if (message == "Notecard") {
            integer notecards = llGetInventoryNumber(INVENTORY_NOTECARD) - 1;
            do {
                if (llGetInventoryName(INVENTORY_NOTECARD, notecards) != "Access") {
                    llGiveInventory(id, llGetInventoryName(INVENTORY_NOTECARD, notecards));
                    llSetObjectDesc(
                        wasKeyValueSet(
                            "notecards",
                            (string)(
                                (integer)(
                                    wasKeyValueGet("notecards", llGetObjectDesc())
                                    ) + 1
                                ),
                            llGetObjectDesc()
                            )
                        );
                }
            } while (--notecards > -1);
            llInstantMessage(id, "Sorry, no notecard is available at this time.");
            jump menu;
        }
        if (message == "URL") {
            llInstantMessage(id, URL);
            llSetObjectDesc(
                wasKeyValueSet(
                    "urls",
                    (string)(
                        (integer)(
                            wasKeyValueGet("urls", llGetObjectDesc())
                            ) + 1
                        ),
                    llGetObjectDesc()
                    )
                );
            jump menu;
        }
        if (message == "Subscribe") {
            if (llListFindList(sList, (list)id) == -1) {
                sList += (list)id + (list)name;
                llInstantMessage(id, SUBSCRIBE_MESSAGE);
                jump menu;
            }
            llInstantMessage(id, SUBSCRIBE_ALREADY_SUBSCRIBED);
            jump menu;
        }
 
        if (llListFindList(aList, (list)name) == -1) return;
 
        if (message == "Dump Subs") {
            integer subscribers = llGetListLength(sList) - 1;
            if(subscribers == -1) {
                llInstantMessage(id, "No subscribers yet.");
                jump time;
            }
            do {
                llInstantMessage(id, llList2String(sList, subscribers) + "#" + llList2String(sList, subscribers - 1));
                subscribers -= 2;
            } while (subscribers > -1);
            jump time;
        }
 
        if(message == "Visitors") {
            llInstantMessage(id, "Visitors: " + (string)((integer)wasKeyValueGet("visitors", llGetObjectDesc())));
            jump time;
        }
 
        if (message == "Statistics") {
            llInstantMessage(id, "---------------------- Statistics ------------------------");
            llInstantMessage(id, "Total number of subscribers: " + 
                (string)(llGetListLength(sList) / 2)
            );
            llInstantMessage(id, "Total number of landmarks handed out: " + 
                (string)(
                    (integer)wasKeyValueGet("landmarks", llGetObjectDesc())
                )
            );
            llInstantMessage(id, "Total number of gifts handed out: " + 
                (string)(
                    (integer)wasKeyValueGet("gifts", llGetObjectDesc())
                )
            );
            llInstantMessage(id, "Total number of notecards handed out: " + 
                (string)(
                    (integer)wasKeyValueGet("notecards", llGetObjectDesc())
                )
            );
            llInstantMessage(id, "Total number of URLs requested: " + 
                (string)(
                    (integer)wasKeyValueGet("urls", llGetObjectDesc())
                )
            );
            llInstantMessage(id, "------------------------------------------------------------");
            jump time;
        }
 
        if (message == "Full Reset") {
            list reset = [ "landmarks", "gifts", "notecards", "urls", "visitors" ];
            do {
                string item = llList2String(reset, 0);
                llSetObjectDesc(wasKeyValueDelete(item, llGetObjectDesc()));
                reset = llDeleteSubList(reset, 0, 0);
            } while(llGetListLength(reset));
            llInstantMessage(id, "The greeter is now resetting...");
            llResetScript();
        }
 
        return;
@menu;
        llDialog(id, DIALOG_MESSAGE, USER_OPTIONS, channel);
@time;
        llSetTimerEvent(60);
    }
 
    sensor(integer num) {
        --num;
        do {
            key agent = llDetectedKey(num);
            if (llListFindList(kList, (list)agent) != -1) jump continue;
            if (llGetFreeMemory() < 2048) kList = llDeleteSubList(kList, 0, 0);
            kList += agent;
            llSetObjectDesc(
                wasKeyValueSet(
                    "visitors",
                    (string)(
                        (integer)(
                            wasKeyValueGet("visitors", llGetObjectDesc())
                            ) + 1
                        ),
                    llGetObjectDesc()
                    )
                );
            llInstantMessage(agent, GREET_MESSAGE);
            integer channel = (integer)("0x8" + llGetSubString(llGetKey(), 0, 6));
            integer com = llListen(channel, "", agent, "");
            if (llListFindList(dialogs, (list)com) == -1) dialogs += com;
            llDialog(agent, DIALOG_MESSAGE, USER_OPTIONS, channel);
@continue;
        } while (--num > -1);
    }
 
    changed(integer change) {
        if (change & CHANGED_INVENTORY) llResetScript();
    }
}

secondlife/greeter.txt ยท Last modified: 2022/11/24 07:46 by 127.0.0.1

Access website using Tor Access website using i2p Wizardry and Steamworks PGP Key


For the contact, copyright, license, warranty and privacy terms for the usage of this website please see the contact, license, privacy, copyright.