// AgentTracker // A specialized sensor that lets modules know if // a specific agent (defined in trackAgent()) goes farther then // X amount of distance (defined in trackAgent()) from the point // it was at when trackAgent() was called. // Copyright (C) 2005-2006 Francisco V. Saldana // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // Francisco V. Saldana can be contacted using his email account // username: dressedinblue, at domain: gmail.com // and in Second Life by IMming Christopher Omega // Triggers an agentOutOfRange(key agentKey) method call if agent // moves out of range. // Methods: // trackAgent(key agentKey, float range) // Starts tracking the specified agent. Ignores subsequent calls // unless stopTrackAgent() is called. // stopTrackAgent(key agentKey) // Stops tracking the specified agent. // A call to trackAgent will start another tracking session. float SENSOR_INTERVAL = 1.0; vector startingPosition = ZERO_VECTOR; float movementRange = 0; key targetAgentKey = NULL_KEY; // ========== For method invocation ========== string randomStr(string chars, integer len) { integer numChars = llStringLength(chars); string ret; integer i; for (i = 0; i < len; i++) { integer randIndex = llFloor(llFrand(numChars)); ret += llGetSubString(chars, randIndex, randIndex); } return ret; } string SEPERATOR_CHARS = "`~!@#$%^&*()-_+[]{}\|'\";/?.>,<"; integer SEPERATOR_LEN = 3; string dumpList2String(list src) { // Generate a seperator not present in any of the // elements in the list. string chars = (string) src; // Squashes all elements together. string seperator; do { seperator = randomStr(SEPERATOR_CHARS, SEPERATOR_LEN); } while (llSubStringIndex(chars, seperator) != -1); return seperator + llDumpList2String(src, seperator); } list parseStringKeepNulls(string src) { // The seperator should be the first SEPERATOR_LEN // characters in the string. return llParseStringKeepNulls(llDeleteSubString(src, 0, SEPERATOR_LEN - 1), [llGetSubString(src, 0, SEPERATOR_LEN - 1)], []); } callMethod(integer callId, string methodName, list parameters) { llMessageLinked(LINK_THIS, callId, dumpList2String(parameters), methodName); } returnValue(string methodName, integer methodIdentifyer, list value) { llMessageLinked(LINK_THIS, methodIdentifyer, dumpList2String(value), methodName + "_ret"); } // ============================================= trigger_agentOutOfRange(key agentKey) { callMethod(0, "agentOutOfRange", [agentKey]); } trigger_pong(string moduleName) { callMethod(0, "pong", [moduleName]); } string this; default { state_entry() { this = llGetScriptName(); } link_message(integer sender, integer num, string parameters, key methodName) { if (methodName == "trackAgent") { list paramList = parseStringKeepNulls(parameters); // Method signature: // trackAgent(key agentKey, float range) key agentKey = (key) llList2String(paramList, 0); float range = (float) llList2String(paramList, 1); targetAgentKey = agentKey; movementRange = range; // Find the agents initial position: llSensor("", targetAgentKey, AGENT, 96, TWO_PI); } else if (methodName == "ping") { list paramList = parseStringKeepNulls(parameters); // Method signature: // ping(string moduleName) string moduleName = llList2String(paramList, 0); if (moduleName == this) trigger_pong(this); } } sensor(integer numDetected) { startingPosition = llDetectedPos(0); state tracking; } no_sensor() { trigger_agentOutOfRange(targetAgentKey); } } state tracking { state_entry() { llSensorRepeat("", targetAgentKey, AGENT, llVecDist(llGetPos(), startingPosition) + movementRange, TWO_PI, SENSOR_INTERVAL); } link_message(integer sender, integer num, string parameters, key methodName) { if (methodName == "stopTrackAgent") { list paramList = parseStringKeepNulls(parameters); // Method signature: // stopTrackAgent(key agentKey) key agentKey = (key) llList2String(paramList, 0); if (agentKey == targetAgentKey || agentKey == NULL_KEY) state default; } else if (methodName == "ping") { list paramList = parseStringKeepNulls(parameters); // Method signature: // ping(string moduleName) string moduleName = llList2String(paramList, 0); if (moduleName == this) trigger_pong(this); } } sensor(integer d) { float distanceMoved = llVecDist(startingPosition, llDetectedPos(0)); if (distanceMoved > movementRange) { trigger_agentOutOfRange(targetAgentKey); state default; } } no_sensor() { trigger_agentOutOfRange(targetAgentKey); state default; } state_exit() { llSensorRemove(); } }