//*************************************************************** // Copyright 2008 Centre For Advanced Spatial Analysis, UCL // // Author: Joel Dearden, University College London // // Contact: j.dearden@ucl.ac.uk // // Joel Dearden, // Centre for Advanced Spatial Analysis, // University College London, // 1-19 Torrington Place, // London, // WC1E 7HB // // // This file is part of SLPedEvac. // // SLPedEvac 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 3 of the License, or // (at your option) any later version. // // SLPedEvac 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 SLPedEvac. If not, see . // //*************************************************************** //CONSTANTS START========================================= integer controlSendCh = -220211; integer controlRecCh = -293321; integer talkToPed = -1; //set on rez integer talkToPMV = -1; //set on rez integer talkToStairEntry = -2929221; //integer INVALID_DESTTYPE = -1; integer EXIT_DESTTYPE = 0; integer SIGN_DESTTYPE = 1; integer STAIRENTRY_DESTTYPE = 2; //integer STAIRTOP_DESTTYPE = 3; integer START_DESTTYPE = 4; integer scanRange = 96; //metres //float viewRange = 0.5; //metres //float halfMoveRange = 0.125; //metres //NOTE: bearing taken from X-axis at zero rotation //vector zeroDirectionVector = <1, 0, 0>; //arbitrary? //NOTE: bearing taken from X-axis at zero rotation // // right hand rule means: // // - positive Z rotation is anti-clockwise when viewed from above // //float lineBarrierLength = 3.1; //metres (added 0.1 metres to prevent agents escaping from small gaps between barriers) //float pointBarrierArcSize; //float lineBarrierArcSize; //float pedestrianArcSize; //float exitArcSize; float minDirMod; float maxDirMod; integer fsNEITHER = 0; integer fsLEFT = 1; integer fsRIGHT = 2; float rough_threshold_flat = 2; //metres float rough_threshold_staircase = 0.5; //metres float localSpcRng = 2; //metres float minLocalSpc = 4.6; //metres squared float maxLocalSpc = 6.8; //metres squared float pedArea = 0.1; //metres square float minFlatVel = 0.4; //m/s float maxFlatVel = 1.5; //m/s float minStaircaseVel = 0.325; //m/s float maxStaircaseVel = 0.8; //m/s integer verticalPMVOffset = 4; //metres //CONSTANTS END========================================= //TODO START========================================= //1-make rays temp on rez //2-make new ray types los & collision //3-update and shorten ray messages //4-make rays long and walls thick //http://wiki.secondlife.com/wiki/Bullet //TODO END========================================= //VARIABLES START========================================= vector dest; integer destType = START_DESTTYPE; integer flatmove = TRUE; list visitedSigns = []; integer destCheckStep = -1; list sensorList = []; integer currentSensorListIndex = -1; integer maxSensorListIndex = -1; //list visiblePointBarrierList = []; //list visibleLineBarrierPosList = []; //list visibleLineBarrierRotList = []; //list visiblePedestrianList = []; //list visibleExitDoorList = []; float currentVelocity = 0; float savedMoveBearing = 0; integer favouredSide = 0; float cumulativeDirectionModifier = 0; integer firstMoveCheck = TRUE; integer usePMV_a = TRUE; //flip flop toggle switch (a, b, a, b, a, ...) string lastLengthMessage = ""; integer atStaircaseTop = FALSE; float slopeAngle; float downSlopeBearing; float staircaseBottomZ; vector flatSlopeDirectionVector; integer lastMoveSafe = FALSE; integer stopWandering = FALSE; //VARIABLES END========================================= //FUNCTIONS START========================================= // getRotToPointAxisAt() // Gets the rotation to point the specified axis at the specified position. // @param axis The axis to point. Easiest to just use an AXIS_* constant. // @param target The target, in region-local coordinates, to point the axis at. // @return The rotation necessary to point axis at target. // Created by Ope Rand, modifyed by Christopher Omega rotation getRotToPointAxisAt(vector axis, vector target) { return llGetRot() * llRotBetween(axis * llGetRot(), target - llGetPos()); } //CastLOSRay(vector target) //{ // llOwnerSay("pedestrian: firing LOS ray at: " + (string)target); //rotation facing = llEuler2Rot(<0, 0, bearingToPos(target)>); //llSetRot(facing); //get rotation between local y-axis and direction vector to target // rotation rezRot = (llRotBetween(<0,1,0> * llGetRot(), (target - llGetPos()))); //start pos is 0.05 metres towards target (ray is 0.1m long) //vector startPos = llGetPos() + ((<0, 0.05, 0> * llGetRot()) * rezRot); // llRezObject("LOSray", llGetPos(), <0, 0, 0>, llGetRot() * rezRot, rayChannel); //} CastLOSRay(vector target) { //we want to fire a LOS ray at the target //llOwnerSay("firing LOS ray at" + (string)target); vector direction = target - llGetPos(); vector velocity = direction / llVecMag(direction); llRezObject( "LOSray", llGetPos(), velocity, ZERO_ROTATION, talkToPed ); } CreatePMV(float bearing) { //rotation PMVrotation = llGetRot() * llEuler2Rot(<0,0,bearing>); rotation facing = llEuler2Rot(<0,0,bearing>); float PMVLength = currentVelocity + 0.125; //setup vector along x-axis... //scaled by current velocity... //rotated by facing... vector createOffsetVector = * facing; //create the pmv llRezObject("PMV", llGetPos() + createOffsetVector + <0,0,verticalPMVOffset>, <0,0,0>, facing, talkToPed); //make sure pmv has time to start listening llSleep(1.0); //send length message lastLengthMessage = "ln:" + (string)PMVLength; llSay(talkToPMV, lastLengthMessage); } //this is the old version CreateStaircasePMV(float bearing) { //calculate horizontal component of offset vector baseOffsetH = ; llOwnerSay("baseOffsetH=" + (string)baseOffsetH); float relativeBearing = relativeBearing(downSlopeBearing, bearing); llOwnerSay("downSlopeBearing=" + (string)downSlopeBearing); llOwnerSay("bearing=" + (string)bearing); llOwnerSay("relativeBearing(downSlopeBearing, bearing)=" + (string)relativeBearing); baseOffsetH *= llEuler2Rot(<0,0,relativeBearing>); llOwnerSay("baseOffsetH after rotation by relativeBearing=" + (string)baseOffsetH); baseOffsetH *= llEuler2Rot(<0,slopeAngle,0>); llOwnerSay("baseOffsetH after rotation by slopeAngle=" + (string)baseOffsetH); //rotate to face bearing baseOffsetH *= llEuler2Rot(<0,0,-relativeBearing>); //undo relative rotation llOwnerSay("baseOffsetH after rotation by -relativeBearing=" + (string)baseOffsetH); baseOffsetH *= llEuler2Rot(<0,0,bearing>); llOwnerSay("baseOffsetH after rotation by bearing=" + (string)baseOffsetH); //got horizontal component.. //== //calculate vertical component of offset vector baseOffsetV = <0, 0, verticalPMVOffset>; llOwnerSay("baseOffsetV=" + (string)baseOffsetV); baseOffsetV *= llEuler2Rot(<0,slopeAngle,0>); llOwnerSay("baseOffsetV after rotation by slopeAngle=" + (string)baseOffsetV); //rotate to down slope bearing baseOffsetV *= llEuler2Rot(<0,0,downSlopeBearing>); llOwnerSay("baseOffsetV after rotation by downSlopeBearing=" + (string)baseOffsetV); //got vertical component.. //create the staircase pmv llRezObject("sPMV", llGetPos() + baseOffsetH + baseOffsetV, <0,0,0>, llEuler2Rot(<0,0,bearing>), talkToPed); //make sure pmv has time to start listening //llSleep(1000); //send length + slope angle + down-slope-bearing message lastLengthMessage = "lns:" + (string)currentVelocity + ";" + (string)slopeAngle + "/" + (string)downSlopeBearing; llSay(talkToPMV, lastLengthMessage); } CreateSPMV(float bearing) { //calculate slope vector vector slopeVector = ; llOwnerSay("slopeVector=" + (string)slopeVector); float relativeBearing = relativeBearing(downSlopeBearing, bearing); llOwnerSay("downSlopeBearing=" + (string)downSlopeBearing); llOwnerSay("bearing=" + (string)bearing); llOwnerSay("relativeBearing(downSlopeBearing, bearing)=" + (string)relativeBearing); slopeVector *= llEuler2Rot(<0,0,relativeBearing>); llOwnerSay("slopeVector after rotation by relativeBearing=" + (string)slopeVector); slopeVector *= llEuler2Rot(<0,slopeAngle,0>); llOwnerSay("slopeVector after rotation by slopeAngle=" + (string)slopeVector); //rotate to face bearing slopeVector *= llEuler2Rot(<0,0,-relativeBearing>); //undo relative rotation llOwnerSay("slopeVector after rotation by -relativeBearing=" + (string)slopeVector); slopeVector *= llEuler2Rot(<0,0,bearing>); llOwnerSay("slopeVector after rotation by bearing=" + (string)slopeVector); //calculate horizontal and vertical components vector h; h.x = slopeVector.x; h.y = slopeVector.y; h.z = 0; vector v; v.x = 0; v.y = 0; v.z = slopeVector.z; //if more than 45* off staircase bearing if(llFabs(relativeBearing) > (PI/2)) { //upslope from pedestrian //rez sPMV at pedPos + flatMovementVector – verticalMovementVector + verticalOffset llRezObject("sPMV", llGetPos() + h + v + <0,0,verticalPMVOffset>, <0,0,0>, llEuler2Rot(<0,0,bearing>), talkToPed); } else { //downslope from pedestrian //rez sPMV at pedPos + flatMovementVector + verticalMovementVector + verticalOffset llRezObject("sPMV", llGetPos() + h - v + <0,0,verticalPMVOffset>, <0,0,0>, llEuler2Rot(<0,0,bearing>), talkToPed); } //make sure pmv has time to start listening llSleep(1.0); //send length + slope angle + down-slope-bearing message lastLengthMessage = "lns:" + (string)currentVelocity + ";" + (string)slopeAngle + "/" + (string)downSlopeBearing; llSay(talkToPMV, lastLengthMessage); } float relativeBearing(float base, float measure) { float angle = measure - base; return angle; } ResendPMVLength() { llSay(talkToPMV, lastLengthMessage); } ConfirmNewPMV() { llSay(talkToPMV, "confirm"); } ClearOldPMV() { llSay(talkToPMV, "clear"); } //CastCOLLISIONRay(float bearing) //{ // rotation facing = llEuler2Rot(<0, 0, bearing>); // llOwnerSay("pedestrian: firing COLLISION ray on bearing: " + (string)bearing); //prevent looking up and down ? //vector casterPos = llGetPos(); //target.z = casterPos.z; //llRotLookAt(getRotToPointAxisAt(<0,1,0>, target), 1.0, 1.0); // llSetRot(facing); //start pos is 0.6 metres along positive Y-axis // vector startPos = llGetPos() + (<0, 0.6, 0> * facing); // llRezObject("COLLISIONray", startPos, <0, 0, 0>, facing, rayChannel); //} integer roughlyEqualFlat(vector a, vector b) { if( (llFabs(a.x - b.x) < rough_threshold_flat) && ((llFabs(a.y - b.y) < rough_threshold_flat) && (llFabs(a.z - b.z) < rough_threshold_flat)) ) { //llOwnerSay("roughlyEqual(" + (string)a + "," + (string)b + ") returns TRUE"); return TRUE; } else { //llOwnerSay("roughlyEqual(" + (string)a + "," + (string)b + ") returns FALSE"); return FALSE; } } integer roughlyEqualStaircase(vector a, vector b) { if( (llFabs(a.x - b.x) < rough_threshold_staircase) && ((llFabs(a.y - b.y) < rough_threshold_staircase) && (llFabs(a.z - b.z) < rough_threshold_staircase)) ) { //llOwnerSay("roughlyEqual(" + (string)a + "," + (string)b + ") returns TRUE"); return TRUE; } else { //llOwnerSay("roughlyEqual(" + (string)a + "," + (string)b + ") returns FALSE"); return FALSE; } } integer roughVectorInList(list checkList, vector pos) { integer i; //llOwnerSay("checkList=" + (string)checkList); for(i = 0; i < llGetListLength(checkList); i++) { if(roughlyEqualFlat(llList2Vector(checkList, i), pos)) { //llOwnerSay("llList2Vector(checkList, i)=" + (string)llList2Vector(checkList, i)); //llOwnerSay("pos=" + (string)pos); //llOwnerSay("are the same"); return TRUE; } } return FALSE; } //converts any bearing into a 0 to 2PI bearing float capBearingRange(float bearing) { if(bearing < 0) { //max should be -2PI bearing = (2 * PI) + bearing; } else { if(bearing > (2 * PI)) { //max should be 4PI bearing = bearing - (2 * PI); } } return bearing; } float distanceBetweenPos(vector posA, vector posB) { vector distVector; distVector.x = posA.x - posB.x; distVector.y = posA.y - posB.y; distVector.z = 0; float dist; dist = llSqrt(llPow((distVector.x), 2) + llPow((distVector.y), 2)); return dist; } //returns the bearing from this object to the specified target in the range 0 to 2PI float bearingToPos(vector target) { //find bearing of target from this pedestrian vector pedPos = llGetPos(); vector directionVector; directionVector.x = target.x - pedPos.x; directionVector.y = target.y - pedPos.y; directionVector.z = 0; float targetBearing; targetBearing = angleBetweenVectors(<1, 0, 0>, directionVector); if(targetBearing < 0) { targetBearing = (2 * PI) + targetBearing; } return targetBearing; } //returns the angle of measure relative to base float angleBetweenVectors(vector base, vector measure) { float angle; //angle of 2 relative to 1= atan2(v2.y,v2.x) - atan2(v1.y,v1.x) angle = llAtan2(measure.y, measure.x) - llAtan2(base.y, base.x); return angle; } //returns the acute angle of b relative to a float acuteAbsoluteAngleBetweenVectors(vector base, vector measure) { float angle; //angle of 2 relative to 1= atan2(v2.y,v2.x) - atan2(v1.y,v1.x) angle = llFabs(llAtan2(measure.y, measure.x) - llAtan2(base.y, base.x)); if(angle > PI) { angle = (2 * PI) - angle; } return angle; } init() { //set textures llSetTexture("f961d62a-300f-fe6d-29df-fd0e04fd1f35", ALL_SIDES); llSetTexture("c172efd0-d6c2-4484-b288-aebe2cab4403", 2); llSetTexture("44eb7ca6-1f6a-4b9f-fe7d-f51688b3dc17", 4); //initially we have reached our dest - forces us to choose a new one at the start; dest = llGetPos(); //pointBarrierArcSize = PI / 16; //radians //lineBarrierArcSize = PI / 2; //radians //pedestrianArcSize = PI / 2; //radians //exitArcSize = PI / 8; //radians //maxNormalTurn = PI / 16; //radians minDirMod = PI / 16; //radians maxDirMod = PI / 8; //radians } //FUNCTIONS END========================================= //STATES START========================================= default { state_entry() { llOwnerSay("wander script ready"); state wait; } } state wait { link_message(integer sender_num, integer num, string list_argument, key id) { if(list_argument == "wander") { llOwnerSay("got message: wander on"); talkToPed = num; talkToPMV = num + 1; state wander; } } } state wander { state_entry() { if(stopWandering) { llOwnerSay("cancelled wander script"); ClearOldPMV(); llSleep(1.0); //send confirmation to main script llMessageLinked(LINK_THIS, 0, "confirmstopwander", NULL_KEY); state wait; } //this just goes through three substates //1) look //2) think //3) act state wander_SUBSTATE_look; } link_message(integer sender_num, integer num, string list_argument, key id) { if(list_argument == "stopwander") { stopWandering = TRUE; } } } state wander_SUBSTATE_look { state_entry() { //calculate current velocity currentVelocity = minFlatVel; state wander_SUBSTATE_raycast_think; } link_message(integer sender_num, integer num, string list_argument, key id) { if(list_argument == "stopwander") { stopWandering = TRUE; } } } state wander_SUBSTATE_raycast_think { state_entry() { //clear any existing PMV - we only ever want one ClearOldPMV(); //if last move not safe set new random direction if(lastMoveSafe != TRUE) { savedMoveBearing = llFrand(2 * PI); } //listen for PMV replies llListen(talkToPed, "", NULL_KEY, ""); //start looping move-test process... cumulativeDirectionModifier = 0; //llOwnerSay("cumulativeDirectionModifier=0"); firstMoveCheck = TRUE; CreatePMV(savedMoveBearing); } listen(integer channel, string name, key id, string message) { if(message == "pmvbroken") { //rez a replacement CreatePMV(capBearingRange(savedMoveBearing + cumulativeDirectionModifier)); } if(message == "lostmsg") { //PMV hasn't received length message //resend previous message ResendPMVLength(); } if(message == "safe") { lastMoveSafe = TRUE; //move OK - keep the new PMV savedMoveBearing += cumulativeDirectionModifier; if(firstMoveCheck == TRUE) { //ATCF move worked - reset favoured side favouredSide = fsNEITHER; } //fix the new PMV ConfirmNewPMV(); state wander_SUBSTATE_act; } if(message == "unsafe") { lastMoveSafe = FALSE; //don't move state wander; } } link_message(integer sender_num, integer num, string list_argument, key id) { if(list_argument == "stopwander") { stopWandering = TRUE; } } } state wander_SUBSTATE_act { state_entry() { //DEBUG //llOwnerSay("act"); //Move the pedestrian a at current velocity in the chosen direction vector eulerBearing = <0, 0, savedMoveBearing>; rotation quatBearing = llEuler2Rot(eulerBearing); //need to rotate to face direction we are moving llSetRot(quatBearing); vector moveVector; //moveVector = <0, 1, 0> * (halfMoveRange + llFrand(halfMoveRange)); moveVector = ; moveVector = moveVector * quatBearing; vector position = llGetPos(); position += moveVector; llSetPos(position); //log move vector pos = llGetPos(); //llHTTPRequest( "
/input.aspx?f=pu&px=" + // (string)pos.x + // "&py=" // + (string)pos.y + // "&u=" /// + (string)llGetKey() + /// "&t=" + // (string)llGetGMTclock(), //[], //"" //); state wander; } link_message(integer sender_num, integer num, string list_argument, key id) { if(list_argument == "stopwander") { stopWandering = TRUE; } } } //STATES END=========================================