Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Discussion: Radar/Scanner

Sable Till
Registered User
Join date: 1 May 2006
Posts: 9
08-17-2006 14:11
Hi, I wrote this little scanner and thought it might be useful. You can stick it in a prim and it llSetTexts the names of everyone nearby and their distance and direction and how long they've been around. I put quite a lot of effort into making it as lag free as possible by having it back off when the sim is overloaded and only scan out as far as necessary.

Anyway, let me know if you have any suggestions or questions or comments.

CODE

//Sable Till - Radar/scannar script.
//You can get a copy of the license this script is under at http://www.gnu.org/copyleft/gpl.html
//Copyright (C) 2006 Sable Till

//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.

string status="none";
list people;
integer maxScanDistance;
vector color = <0,1,1>;
integer maxPeople = 8;
integer scanType = AGENT;
integer scanFreq=1;

integer count(string name) {
integer i = llListFindList(people, [name]);
if(i ==-1){
people+=[name, 0];
return 0;
} else {
integer count = llList2Integer(people, i+1);
people=llListReplaceList(people, [count+scanFreq], i+1, i+1);
return count;
}
}

//calculate time strings with proper units that are sensibly rounded
string time(integer cnt) {
if(cnt>3600) {
return (string)(cnt/3600)+"hr " + (string)((cnt%3600)/60) +"min";
}else {
if(cnt>60) {
return (string)(cnt/60)+"min";
} else {
return (string)cnt+"s";
}
}
}

//I'm pretty sure there's a better way to do this but I'm trying to calculate the angle between
//North and the target so I can work out which direction it is in.
float getAngle(vector me, vector target) {
float hyp = llVecDist(me, target);
float yDiff = target.y-me.y;
float xDiff = target.x-me.x;
float angle = llSin(yDiff/hyp);
if(xDiff>0 && yDiff>0) {
return angle*RAD_TO_DEG;
}
if(xDiff>0 && yDiff<0) {
return 90-angle*RAD_TO_DEG;
}
if(xDiff<0 && yDiff>0) {
return angle*RAD_TO_DEG+270;
}
if(xDiff<0 && yDiff<0) {
return angle*RAD_TO_DEG + 270;
}
return angle*RAD_TO_DEG;
}

default
{
state_entry()
{
llSensorRepeat("", "",scanType, 96, PI, scanFreq);
llSetTimerEvent(6);
}

sensor(integer num_detected) {
people=[];
string result;
integer n=-1;
integer distance=0;
integer detDist;
string name;

vector pos = llGetPos();
//get the dist, name and direction of everyone we just scanned.
for(n=0;n<num_detected && n<maxPeople;++n) {
vector detPos = llDetectedPos(n);
detDist = (integer)llVecDist(pos, detPos);
float angle = getAngle(llGetPos(), detPos);
name = llKey2Name(llDetectedKey(n));
if(detDist<96) {
people+=detDist;
people+=name;
people+=angle;
}
}
//sort the strided list
people = llListSort(people, 3, TRUE);
//construct settext
num_detected = llGetListLength(people)/3;
for(n=0;n<num_detected;++n) {
detDist=llList2Integer(people, n*3);
name = llList2String(people, n*3+1);
float dir = llList2Float(people, n*3+2);
if(detDist>20 && distance<=20) {
result+="<- Chat Range Limit ->\n";
}
result+=name;
if(detDist<20) {
integer cnt = count(name);
result+=" ["+time(cnt)+"]";
}
result+=" ["+(string)detDist+"m]";

if(dir < 0 || dir > 360) {
llOwnerSay("Error:"+(string)dir+":"+name);
}
//determine which compass direction they are in.
if(dir <= 22.5) {
result+=" N\n";
} else {
if(dir > 22.5 && dir <= 67.5) {
result+=" NE\n";
} else {
if(dir > 67.5 && dir <= 112.5) {
result+=" E\n";
} else {
if(dir > 112.5 && dir <= 157.5) {
result+=" SE\n";
} else {
if(dir > 157.5 && dir <= 202.5) {
result+=" S\n";
} else {
if(dir > 202.5 && dir <= 247.5) {
result+=" SW\n";
} else {
if(dir > 247.5 && dir <= 292.5) {
result+=" W\n";
} else {
if(dir > 292.5 && dir <= 337.5) {
result+=" NW\n";
} else {
if(dir > 337.5 && dir < 360) {
result+=" N\n";
}
}
}

}}}}}}

distance=detDist;
}


//If we detected more (or the same number of) people as maxPeople then shrink down the scan distance to just
//the distance to the furthest one. Otherwise increment it a bit in case there are people further out.
if(num_detected>=maxPeople) {
maxScanDistance=distance+10;
} else {
maxScanDistance+=10;
}

result+="\nStatus:"+status;
//adjust max people based on the length of result
if(llStringLength(result)>254) {
maxPeople--;
llOwnerSay("Length is "+(string)llStringLength(result) +
" Decrementing maxPeople to "+(string)maxPeople);
} else {
if(llStringLength(result)<200) {
maxPeople++;
llOwnerSay("Length is "+(string)llStringLength(result) +
" Incrementing maxPeople to "+(string)maxPeople);
}
}
llSetText(result, color, 1);
}

no_sensor() {
llSetText("Status:"+status, color, 1);
maxScanDistance+=10;
llSensorRepeat("", "", scanType, maxScanDistance, PI, scanFreq);
}

//all we do here is check the sims fps and dilation and tone down our scanning if necessary.
timer() {
float fps = llGetRegionFPS();
float timeDilation = llGetRegionTimeDilation();

integer scanDistance;
if(fps<35 || timeDilation <0.9) {
if(maxScanDistance>30) {
scanDistance=30;
}
scanFreq=240;
status = "poor";
llSetTimerEvent(240);
color=<1,0,0>;
} else
{
if(fps<40 || timeDilation<0.95) {
if(maxScanDistance>64) {
scanDistance=64;
} else {
scanDistance=maxScanDistance;
}
scanFreq=30;
status = "ok";
llSetTimerEvent(120);
color=<1,1,0>;
} else
{
if(maxScanDistance>96) {
scanDistance=96;
} else {
scanDistance=maxScanDistance;
}
scanFreq=1;
llSetTimerEvent(60);
status = "good";
color=<0,1,1>;
}}
llSensorRepeat("", "", scanType, scanDistance, PI, scanFreq);
}

}
Nada Epoch
The Librarian
Join date: 4 Nov 2002
Posts: 1,423
Original Thread
08-17-2006 18:04
/15/e2/130768/1.html
_____________________
i've got nothing. ;)
Esch Snoats
Artist, Head Minion
Join date: 2 May 2006
Posts: 261
08-17-2006 20:36
I love this, but I was wondering how hard it would be to modify it so that it only tells me when someone is near within a certain distance, instead of giving me exact coords and all that? I'm interested in using it at my business so that it informs me everytime someone goes there while I'm outside the parcel. Thanks!

E
Vincent Nacon
Reseacher & Developer
Join date: 1 Mar 2006
Posts: 111
08-20-2006 07:52
Very nice work! At first, I thought it was a rip off from Sru's Simple Hovertext Radar (a freebie). I look into it and gave it a try. It has similar hovertext radar idea, but better and along with 2 more ideas.

And I am glad this is a open-source. You need a reward.
Sable Till
Registered User
Join date: 1 May 2006
Posts: 9
08-20-2006 08:02
Thanks. Obviously the /idea/ is ripped off of a number of similar products. But I've never seen anyone elses code for something like this.

I've spotted a few bugs and so on and been keeping the wiki page updated http://secondlife.com/badgeo/wakka.php?wakka=LibraryRadar. So if anyone comes to this thread in six months check there because it'll be newer than the code here.
Learjeff Innis
musician & coder
Join date: 27 Nov 2006
Posts: 817
11-30-2006 10:08
Nifty script!

Is there a reason you didn't use the following form for the cascading if-else's?
CODE

if(dir <= 22.5) {
result+=" N\n";
} else if(dir > 22.5 && dir <= 67.5) {
result+=" NE\n";
} else if(dir > 67.5 && dir <= 112.5) {
result+=" E\n";
} else if(dir > 112.5 && dir <= 157.5) {
result+=" SE\n";
} else if(dir > 157.5 && dir <= 202.5) {
result+=" S\n";
} else if(dir > 202.5 && dir <= 247.5) {
result+=" SW\n";
} else if(dir > 247.5 && dir <= 292.5) {
result+=" W\n";
} else if(dir > 292.5 && dir <= 337.5) {
result+=" NW\n";
} else if(dir > 337.5 && dir < 360) {
result+=" N\n";
}

Easier to read.
Learjeff Innis
musician & coder
Join date: 27 Nov 2006
Posts: 817
11-30-2006 10:50
Also, to convert from degrees to 16-point compass direction, you could use something like this:
CODE
list compass_dirs = [  // 16-point table
"N", "NNE", "NE", "ENE",
"E", "ESE", "SE", "SSE",
"S", "SSW", "SW", "WSW",
"W", "WNW", "NW", "NNW",
"N"
];

integer points = 16;

float deg_per_point = 360.0 / points;
float deg_offset = deg_per_point / 2;

string compass_dir(deg)
{
return compass_dirs[(integer)((deg + deg_offset)/deg_per_point)];
}


Might be typos; I tested it in python and converted to LSL without compiling & testing the LSL. Of course, if you want an 8-point compass (N, NE, E, etc.), just remove the 3-letter directions from the list, and change "points" from 16 to 8.
Elanthius Flagstaff
Registered User
Join date: 30 Apr 2006
Posts: 1,534
11-30-2006 11:55
I have a policy of always wrapping blocks of if statements in {...} even if they are theoretically only one line. Seen too many people add an extra line and then forget the braces need to be added. I guess your way is fine too.

From: Learjeff Innis
Nifty script!

Is there a reason you didn't use the following form for the cascading if-else's?
CODE

if(dir <= 22.5) {
result+=" N\n";
} else if(dir > 22.5 && dir <= 67.5) {
result+=" NE\n";
} else if(dir > 67.5 && dir <= 112.5) {
result+=" E\n";
} else if(dir > 112.5 && dir <= 157.5) {
result+=" SE\n";
} else if(dir > 157.5 && dir <= 202.5) {
result+=" S\n";
} else if(dir > 202.5 && dir <= 247.5) {
result+=" SW\n";
} else if(dir > 247.5 && dir <= 292.5) {
result+=" W\n";
} else if(dir > 292.5 && dir <= 337.5) {
result+=" NW\n";
} else if(dir > 337.5 && dir < 360) {
result+=" N\n";
}

Easier to read.