04-24-2005 20:12
Since we can no longer respond to Hotline posts, Solar doesn't have IM going, and this is a good point for others:

/invalid_link.html

From: Solar Angel
I have a few ideas for innovative transportation systems, but I'm having serious trouble implementing them due to limitations of the scripting system.

The basic problem comes down to the task of getting from point "A" to point "B", when A and B are on opposite sides of the grid but still part of the connected, contiguous regions. It's easy enough to do manually: just teleport to the nearest telehub and fly the remaining distance. There is, however, no way through a script to launch a long-range teleport.

Short range is easy (the llSitTarget hack). Medium range is not that difficult (a basic follow-script with hole tracing can move you there in a handful of seconds, and even though it isn't really "teleporting", it still works).

There is, however, nothing for really long range. lsl is too slow and limited to make a really effective directed-graph path follower, the grid is too full of holes for a basic "turn-right" maze-solver to succeed, and even if either of those worked (say, by using an external maze-solver linked in through XML-RPC), it would take many minutes to arrive.

How about a script command to move an object (and, by extension, any avatar sitting on it) to the nearest telehub to a global coordinate set? Or even extend llLoadURL to support the secondlife:// protocol? I personally agree with the decision to not make point-to-point scripted long-range teleports easy, but surely point-to-telehub should be available?

Actually, I'd been working on a "rough" pathfinder that utilizes the newer features of 1.6. This allows users to get away from the stigma of "giant lists storing sim data," especially today where that would have required line after line after line of sim coordinates.

The following, then, is some rough code that could serve as the basis for what it is you want to do. Since it's fairly "rough," I have not decided to release it to the Script Library just yet. Furthermore, it has been done before by others using the methods I've described.

CODE
// Edit these variables here:

// Target Sim:
string region = "Rose";

// Location in Sim
vector loc = <100,100,50>;


// Advanced Variables:

integer max_tries = 100; // Max number of traceback routines
float fly_height= 400; // Height to fly in world units
integer speed = 20; // Speed for physical movement
integer same_sim_tries = 5; // Failsafe count before use back is triggered

// Standard Flags:

integer use_back = TRUE; // Depending, this might help the pathfinder WORK!
integer use_phys = TRUE; // Use physics
integer ignore_init = TRUE; // Ignores initialization movement

// Physics Flags:

integer drunk_driver = FALSE; // One wild ride!
integer use_exact = TRUE; // Use exact coords; countered by drunk_driver
// Set drunk_driver and use_exact to FALSE and use_phys to TRUE to initiate
// my best attempt at a vehicle-less autopilot. Enjoy!


list path = []; // Lists path already taken. Good for statistical data or,
// here, knowing if we came from a sim already.
key sim_stuffs = ""; // For Data Request

pathTo(vector location)
{
integer same_sim = 0; // Same sim count. Failsafe.
integer try = 0; // Initialize our first try variable
integer traceback = FALSE; // Traceback variable if we dead-end
vector init = llGetPos(); // Initialize our position
init.z = fly_height;

if(use_phys)
{
llMoveToTarget(llGetPos(),0.3);
llSetStatus(STATUS_PHYSICS,TRUE);
}

if(!ignore_init)
{
if(!use_phys)
{
while(llGetPos() != init)
llSetPos(init);
}
else
{
while(llVecMag(llGetPos() - init) > speed)
llMoveToTarget(llGetPos() + llVecNorm(init - llGetPos()) * speed,0.3);
}
}

while(try < max_tries) // Start up the meat of our function
{
vector global = llGetPos() + llGetRegionCorner();
vector diff = location + <0,128,0> - global;
vector target = <0,0,0>;
integer is_next = FALSE;
if(llListFindList(path,(list)llGetRegionCorner()) == -1)
path += llGetRegionCorner();
else
same_sim++;

if(llGetRegionName() == region)
{
thisSim();
return;
}
if(llAbs((integer)diff.x) > llAbs((integer)diff.y))
{
if(diff.x < 0)
{
if(!llEdgeOfWorld(<128,128,0>, <-256,0,0>) && llListFindList(path,[llGetRegionCorner() + <-256,0,0>]) == -1)
target = llGetRegionCorner() + <-128,128,0>;
else
{
if(diff.y < 0)
{
if(!llEdgeOfWorld(<128,128,0>, <0,-256,0>) && llListFindList(path,[llGetRegionCorner() + <0,-256,0>]) == -1)
target = llGetRegionCorner() + <128,-128,0>;
}
if(target == <0,0,0>)
{
if(!llEdgeOfWorld(<128,128,0>, <0,256,0>) && llListFindList(path,[llGetRegionCorner() + <0,256,0>]) == -1)
target = llGetRegionCorner() + <128,384,0>;
}
if(target == <0,0,0>) traceback = TRUE;
}
}
else
{
if(!llEdgeOfWorld(<128,128,0>, <256,0,0>) && llListFindList(path,[llGetRegionCorner() + <256,0,0>]) == -1)
target = llGetRegionCorner() + <384,128,0>;
else
{
if(diff.y < 0)
{
if(!llEdgeOfWorld(<128,128,0>, <0,-256,0>) && llListFindList(path,[llGetRegionCorner() + <0,-256,0>]) == -1)
target = llGetRegionCorner() + <128,-128,0>;
}
if(target == <0,0,0>)
{
if(!llEdgeOfWorld(<128,128,0>, <0,256,0>) && llListFindList(path,[llGetRegionCorner() + <0,256,0>]) == -1)
target = llGetRegionCorner() + <128,384,0>;
}
if(target == <0,0,0>) traceback = TRUE;
}
}
}
else
{
if(diff.y < 0)
{
if(!llEdgeOfWorld(<128,128,0>, <0,-256,0>) && llListFindList(path,[llGetRegionCorner() + <0,-256,0>]) == -1)
target = llGetRegionCorner() + <128,-128,0>;
else
{
if(diff.x < 0)
{
if(!llEdgeOfWorld(<128,128,0>, <-256,0,0>) && llListFindList(path,[llGetRegionCorner() + <-256,0,0>]) == -1)
target = llGetRegionCorner() + <-128,128,0>;
}
if(target == <0,0,0>)
{
if(!llEdgeOfWorld(<128,128,0>, <256,0,0>) && llListFindList(path,[llGetRegionCorner() + <256,0,0>]) == -1)
target = llGetRegionCorner() + <384,128,0>;
}
if(target == <0,0,0>) traceback = TRUE;
}
}
else
{
if(!llEdgeOfWorld(<128,128,0>, <0,256,0>) && llListFindList(path,[llGetRegionCorner() + <0,256,0>]) == -1)
target = llGetRegionCorner() + <128,384,0>;
else
{
if(diff.x < 0)
{
if(!llEdgeOfWorld(<128,128,0>, <-256,0,0>) && llListFindList(path,[llGetRegionCorner() + <-256,0,0>]) == -1)
target = llGetRegionCorner() + <-128,128,0>;
}
if(target == <0,0,0>)
{
if(!llEdgeOfWorld(<128,128,0>, <256,0,0>) && llListFindList(path,[llGetRegionCorner() + <256,0,0>]) == -1)
target = llGetRegionCorner() + <384,128,0>;
}
if(target == <0,0,0>) traceback = TRUE;
}
}
}


if(traceback)
{
try++;
integer path_back = llListFindList(path,[llGetRegionCorner()]);
if(llListFindList(path,[llGetRegionCorner()]) == -1)
path_back = llGetListLength(path) - 1;

// See if any sim is open nearby if use_back is set
if(use_back || llGetRegionCorner() == llList2Vector(path,0) || same_sim > same_sim_tries)
{
if(!llEdgeOfWorld(<128,128,0>, <-256,0,0>) && llListFindList(path,[llGetRegionCorner() + <-256,0,0>]) == -1)
target = llGetRegionCorner() + <-128,128,0>;
else if(!llEdgeOfWorld(<128,128,0>, <256,0,0>) && llListFindList(path,[llGetRegionCorner() + <256,0,0>]) == -1)
target = llGetRegionCorner() + <384,128,0>;
else if(!llEdgeOfWorld(<128,128,0>, <0,-256,0>) && llListFindList(path,[llGetRegionCorner() + <0,-256,0>]) == -1)
target = llGetRegionCorner() + <128,-128,0>;
else if(!llEdgeOfWorld(<128,128,0>, <0,256,0>) && llListFindList(path,[llGetRegionCorner() + <0,256,0>]) == -1)
target = llGetRegionCorner() + <128,384,0>;
same_sim = 0;
}

// If all else fails, go back along the path we took
if(target == <0,0,0>) target = llList2Vector(path,path_back - 1) + <128,128,0>;
traceback = FALSE;
}

if(ignore_init && llVecMag(<location.x,location.y,0> + <128,128,0> - <target.x,target.y,0>) < 10)
{
is_next = TRUE;
target = (location + loc) - (1 / 5 * (loc + location - llGetPos() - llGetRegionCorner()));
}

if(llGetStatus(STATUS_PHYSICS))
{
while(llVecMag(<target.x,target.y,0> - <global.x,global.y,0>) > speed * 5)
{
global = llGetPos() + llGetRegionCorner();
vector place = llGetPos() + target - global;
if(!is_next) place.z = fly_height;
if(use_exact)
{
llMoveToTarget(llGetPos() + (llVecNorm(place - llGetPos()) * speed),0.3);
llLookAt(llGetPos() + llVecNorm(place - llGetPos()) * speed,0.3,0.3);
}
else
{
vector between;
between = llRot2Euler(llRotBetween(llRot2Up(llGetRot()),llVecNorm(place - llGetPos())));
if(!drunk_driver)
{
vector between2 = llRot2Euler(llRotBetween(llVecNorm(place - llGetPos()),llRot2Up(llGetRot())));
if(llVecMag(llVecNorm(between) + llRot2Up(llGetRot())) < 1.1 && llVecMag(llRot2Up(llGetRot()) + llVecNorm(place - llGetPos())) > 1)
between = between2;
}

rotation two = llGetRot() * llEuler2Rot(0.1 * between);
llLookAt(llGetPos() + (<0,0,1> * two),0.3,0.3);
llMoveToTarget(llGetPos() + llRot2Up(llGetRot()) * speed,0.3);

}
llSleep(0.2);
}
}
else
{
while(target.x != global.x || target.y != global.y)
{
global = llGetPos() + llGetRegionCorner();
vector place = llGetPos() + target - global;
place.z = fly_height;
llSetPos(place);
llSleep(0.1);
}
}

}
}

thisSim()
{
float ground = llGround(loc - llGetPos());
if(llScriptDanger(loc) && loc.z < ground + 20)
loc.z = ground;
else if(loc.z < ground)
loc.z = ground;

if(llGetStatus(STATUS_PHYSICS))
{
while(llVecMag(llGetPos() - loc) > speed)
{
llMoveToTarget(llGetPos() + llVecNorm(loc - llGetPos()) * speed,0.3);
llLookAt(llGetPos() + llVecNorm(loc - llGetPos()) * speed,0.3,0.3);
}
}
else
{
while(llGetPos() != loc)
llSetPos(loc);
}
llSetStatus(STATUS_PHYSICS,FALSE);
llStopLookAt();
llStopMoveToTarget();
vector rot = llRot2Euler(llGetRot());
llSetRot(llEuler2Rot(<PI + PI_BY_TWO,rot.y,PI_BY_TWO>));
}

default
{
touch_start(integer total_number)
{
sim_stuffs = llRequestSimulatorData(region,DATA_SIM_POS);
}
dataserver(key query, string data)
{
if(query == sim_stuffs)
pathTo((vector)data);
}
}

At any rate, that's just a minor caveat for the evening. There any interest in another pathfinder in the Library?

This also serves as a neat basis for testing the speed of nested if loops, much like those discussed in Hiro's earlier thread, which I'm having trouble finding.
_____________________
---