/* BUG FIX: Line 517 had llOwnerSay and admins couldn't see message replaced with llRegionSayTo Updated to include a dialog to ask if visitor would like a landmark on September 18th 2023 Updated to offer multiple notecards Feel free to edit/play and use as you wish. NOTES about greeting: script will replace /FIRST/ with first name of avatar if you want both names replace with /FULL/ if you wish to replace with Miss, Ms or Mr or Master use /FORMAL/ Greeter will strip @gridname.xxx:???? when greeting avatars displaying their name but will store full name in the greeter logs. If you don't want avatars name displayed in the greeting simply omit /FIRST/ /FORMAL/ and /FULL/ from the greeting. Use \n for a carriage return within greeting. */ //////////////////// START USER DEFINED SETTINGS \\\\\\\\\\\\\\\\\\\\\\\\ // If you want to give visitor a landmark/Notecard, simply place one inside of this object. // If you don't want a dialog sent to visitors set to false; // If set to false and if landmark inside a landmark sent automatically // when set to TRUE visitor asked if they want a landmark, if inside. integer SendDialog = TRUE; // Examples: If the notecard contains rules of your region set this name to rules // OR if contains land prices set to something brief like Rental or Land string Notecard_Button_Name = "RULES"; // string Greeting = "Welcome /FORMAL/!\nShould you have any questions do contact me."; // string Greeting = "Welcome /FULL/. Call me should you have any questions."; // string Greeting = "Thanks for dropping by /FIRST/. Have fun!"; // string Greeting = "Welcome to Covert Gadgets, /FIRST/.\nPlease reach out and IM /OWNER/ to answer any questions you may have." // /OWNER/ is replaced with a clickable link to your ptofile string Greeting = "Welcome to my humble abode, /FORMAL/!\nHave a question? Contact /OWNER/ "; /* Used to use your local time in the greeter logs Does not account for daylight saving set to your countries UTC/GMT offset Example: if you live in London set value to 0.0 If you live in Germany set to 1.0 If Australian east coast 10.0, USA Central -7.0 */ integer UTC = 10; // Set the maximum number of log entries to keep integer LogLimit = 100; // Setting to 5 seconds is a good setting putting less drain on a region resources float ScanFrequency = 5.0; // How far to scan for visitors. This is ignored if you choose to // scan entire region. float ScanRange = 50.0; list ScanType = ["This Land", "My Land", "Whole Region"]; integer iScanType = 0; //////////////////// END USER DEFINED SETTINGS \\\\\\\\\\\\\\\\\\\\\\\\ string NotecardAdmins = "admins_list"; string NotecardWhite = "white_list"; // Used for toggling the on/off switch for the greeter integer POWER = FALSE; list Visitors = []; list HERE = []; list WhiteList = []; // Don't put you or admins into whitelist list Admins = []; // as Admins are automatically white listed integer channel; integer Landmark_Channel; integer Landmark_Handle; integer handle; integer ExpireMenu = -1; list Notecards = []; COLLECT_NOTECARDS() { integer a; integer b = llGetInventoryNumber(INVENTORY_NOTECARD); Notecards = []; if(b == 0) return; string ncName; for(a=0;a 0) { llOwnerSay("I'll offer the landmark [" + llGetInventoryName(INVENTORY_LANDMARK,0) + "] to visitors"); } /* test for existance of notecards for white and admin lists and loads them Performs basic systax check. If name contains SPACE or PERIOD name will be loaded and converted into lowercase. */ COLLECT_NOTECARDS(); integer line; integer lines; string data; llOwnerSay("Loading settings....."); // Check if admin NC exists, if so load it if(llGetInventoryType(NotecardAdmins) == INVENTORY_NOTECARD){ llOwnerSay("Loading admins."); lines = osGetNumberOfNotecardLines(NotecardAdmins); if(lines == 0) { // skip loading if notecard empty llOwnerSay("Error. Admin list empty!"); } else { // clear admin list and loads new from NC Admins = []; for(line = 0;line < lines; line++) { data = llStringTrim(osGetNotecardLine(NotecardAdmins,line),STRING_TRIM); // Syntax checking line not empty and contains valid name if (data != "" && (llSubStringIndex(data," ") != -1 || llSubStringIndex(data,".") != -1) ) { llOwnerSay("Added " + data + " to admins"); Admins += llToLower(data); } } } } else { llOwnerSay(NotecardAdmins + " missing and not loaded."); } // Check if white NC exists, if so load it if(llGetInventoryType(NotecardWhite) == INVENTORY_NOTECARD){ llOwnerSay("Loading white list."); lines = osGetNumberOfNotecardLines(NotecardWhite); if(lines == 0) { // skip loading if notecard empty llOwnerSay("Error. White list empty!"); } else { // clear whitelist and loads new from NC WhiteList = []; for(line = 0;line < lines; line++) { data = llStringTrim(osGetNotecardLine(NotecardWhite,line),STRING_TRIM); // Syntax checking line not empty and contains valid name if (data != "" && (llSubStringIndex(data," ") != -1 || llSubStringIndex(data,".") != -1) ) { llOwnerSay("Added " + data + " to white list"); WhiteList += llToLower(data); } } } } else { llOwnerSay(NotecardWhite + " missing and not loaded."); } llOwnerSay("Completed loading settings."); } CLEAN(){ /* To prevent persons already greeted they are placed onto the HERE list. When they leave the region their names removed from the HERE list amd when return, greeted again. */ integer b = llGetListLength(HERE); if(b == 0) return; integer a; /* count backwards chceking if avatar still here if not delete from HERE list */ for(a = b-1;a>-1;a--) { // If avatars SIZE returns ZERO they are not in region // If not in region, remove from HERE list if(llGetAgentSize(llList2Key(HERE,a)) == ZERO_VECTOR) HERE = llDeleteSubList(HERE,a,a); } } integer WHITE(string name){ if(llListFindList(Admins,[name]) != -1) return TRUE; if(llListFindList(WhiteList,[name]) != -1) return TRUE; return FALSE; } integer RANGE(vector pos){ // If scaning whole region ignore renge setting if(iScanType == 2) return TRUE; if(llVecDist(llGetPos(),pos) < ScanRange) return TRUE; return FALSE; } SCAN() { // Remove names of avatars no longere in region CLEAN(); // Begin get UUID of all avatars in this region list AGENTS; integer a; integer b; key id; vector pos; key myland; key yourland; myland = llList2Key(llGetParcelDetails(llGetPos(),[2]),0); // 2 = PARCEL_DETAILS_OWNER if(iScanType == 0) AGENTS = llGetAgentList(AGENT_LIST_PARCEL, []); else if(iScanType == 1) AGENTS = llGetAgentList(AGENT_LIST_PARCEL_OWNER, []); else AGENTS = llGetAgentList(AGENT_LIST_REGION, []); b = llGetListLength(AGENTS); if(b == 0 ) return; for(a=0;a LogLimit) Visitors = llDeleteSubList(Visitors,0,0); string msg; if(llSubStringIndex(Greeting,"/OWNER/") != -1) msg = osReplaceString(Greeting, "/OWNER/", "secondlife:///app/agent/"+(string)llGetOwner()+"/about ", -1, 0); else msg = Greeting; if(llSubStringIndex(Greeting,"/FIRST/") != -1) msg = osReplaceString(msg, "/FIRST/", first, -1, 0); else if(llSubStringIndex(msg,"/FORMAL/") != -1) msg = osReplaceString(msg, "/FORMAL/", FormalName(name,id), -1, 0); else if(llSubStringIndex(msg,"/FULL/") != -1) msg = osReplaceString(msg, "/FULL/", first + " " + LastName(name), -1, 0); llRegionSayTo(id,0,msg); integer lm = llGetInventoryNumber(INVENTORY_LANDMARK); integer nc = llGetListLength(Notecards); if(SendDialog == FALSE) { if(lm != 0) llGiveInventory(id,llGetInventoryName(INVENTORY_LANDMARK,0)); if(nc != 0) for(a=0;a23) {Hour = Hour - 24;Day++;} else if(Hour<0) {Hour = Hour + 24;Day--;} if(Day > DAYS) {Month++;Day = 1;} else if(Day<1) { Month--; if(Month < 1) { Month = 12; Year--; } Day = llList2Integer(DaysPerMonth,Month-1); if(LEAPYEAR(Year) && Month == 2) Day = 29; } if(Month>12) {Month = 1;Year++;} string data = "["+(string)Year+"-"; if(Month < 10) data += "0"+(string)Month;else data += (string)Month; if(Day < 10) data += "-0"+(string)Day;else data += "-"+(string)Day; if(Hour < 10) data += " 0"+(string)Hour;else data += " "+(string)Hour; if(Min < 10) data += ":0"+(string)Min;else data += ":"+(string)Min; if(Sec < 10) data += " 0"+(string)Sec;else data += " "+(string)Sec; data +="] "; return data; } default { changed( integer change) { /* If a change within object detected it will be assumed the admin and or white list has been altered and will be reloaded. A change can occure if you alter a NC, remove or add an NC landmark, object, landmark or texture. */ if( change & CHANGED_INVENTORY) LOAD_SETTINGS(); if(change & CHANGED_OWNER) INI(); } on_rez(integer i) { /* You may want to remove this. If you remove it allows you to take it into inventory and rez into a new location without the losing logs */ INI(); } state_entry() { LOAD_SETTINGS(); // Landmark channel remains open for simplifying the code // you could write more complex code to open and close for each visitor // is it really worth it? Landmark_Channel = 0-((integer)llFrand(5000000)) - 550000; Landmark_Handle = llListen(Landmark_Channel,"","",""); } touch_end(integer i){ key id = llDetectedKey(0); /* Check if person touching is you or an admin If not exit with message */ if(!AUTH(id)) { // using regionsay is more efficent and faster than // using instantmessage. (No 1 second delay) llRegionSayTo(id,0,"Not authorised to use me."); return; } MENU(id); } listen(integer ch, string name, key id, string msg) { integer a; integer b; /* Process channel used for visitor response to question when asked if they want a landmark, notecard or all For simplification of code the channel remains open */ if(ch == Landmark_Channel){ if(llGetInventoryNumber(INVENTORY_LANDMARK) > 0 && (msg == "Landmark" || msg == "ALL")) llGiveInventory(id,llGetInventoryName(INVENTORY_LANDMARK,0)); b = llGetListLength(Notecards); if(b > 0 && (msg == Notecard_Button_Name || msg == "ALL")) { for(a=0;a