//*************************************************************** // 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 . // //*************************************************************** integer talk_to_pedestrian = -1; //set on rez integer talk_to_pmv = -1; //set on rez list barrierObjectCodes = ["wal", "CMV", "TMV", "fur", "ped"]; //list barrierObjectCodes = ["wal", "CMV", "TMV", "fur"]; float allClearTimeout = 6; //seconds float moveDownDelay = 3; //seconds vector targetPos; //set on rez float verticalOffset = 4; //metres float maxRangeToTarget = 10; key ownerPedKey = ""; //set by chat message float timestamp; //set on rez float retryTime = 20; //seconds safe() { //return to normal prim so other PMVs can detect me llVolumeDetect(FALSE); llSetStatus( STATUS_PHYSICS, FALSE); llSetStatus( STATUS_PHANTOM, FALSE); //listen for confirm messages from pedestrian (before sending "safe" message otherwise we might miss a quick reply) llListen(talk_to_pmv, "", NULL_KEY, ""); llSetColor(<0,1,0>, ALL_SIDES); llSay(talk_to_pedestrian, "safe"); llOwnerSay("CS: PMV thinks its safe"); } unsafe() { llSetColor(<1,0,0>, ALL_SIDES); llSay(talk_to_pedestrian, "unsafe"); llOwnerSay("CS: PMV doesn't think its safe"); llDie(); } vector localXDirection() { //returns direction vector for local x vector localX = <1,0,0> * llGetRot(); return localX; } vector localYDirection() { //returns direction vector for local y vector localY = <0,1,0> * llGetRot(); return localY; } vector localZDirection() { //returns direction vector for local z vector localZ = <0,0,1> * llGetRot(); return localZ; } default { state_entry() { llSetText("default:state entry", <0,0,0>,1); llSetColor(<0,0,1>, ALL_SIDES); llOwnerSay("state_entry"); } on_rez(integer start_param) { llSetText("default:on_rez", <0,0,0>,1); llOwnerSay("on_rez"); llSetObjectName("PMV"); talk_to_pedestrian = start_param; talk_to_pmv = start_param + 1; state waiting; } } state waiting { state_entry() { llSetText("waiting:state entry", <0,0,0>,1); llOwnerSay("waiting_state_entry"); //PMV has just been created //listen for length scale message llListen(talk_to_pmv, "", NULL_KEY, ""); //if messages get lost we might need to poke the pedestrian to resend llSetTimerEvent(retryTime); } listen(integer channel, string name, key id, string message) { llOwnerSay("got message: " + message); if(channel == talk_to_pmv) { if(llGetSubString(message, 0, 3) == "lns:") { //save owner ped key from message - so we can ignore it later when detecting collisions ownerPedKey = id; //slip message data into usable parts integer delimiterIndexA = llSubStringIndex(message, ";"); integer delimiterIndexB = llSubStringIndex(message, "/"); float newLength = (float)llGetSubString(message, 4, delimiterIndexA - 1); float slopeAngle = (float)llGetSubString(message, delimiterIndexA + 1, delimiterIndexB - 1); float downSlopeBearingAngle = (float)llGetSubString(message, delimiterIndexB + 1, -1); //llSetRot(llEuler2Rot(<0,0,0>)); //rotate to match slope angle //llSetRot(llGetRot() * llEuler2Rot(<0, slopeAngle, 0>)); //rotate to match down slope bearing //llSetRot(llGetRot() * llEuler2Rot(<0, 0, downSlopeBearingAngle>)); //scale to correct size vector scale = llGetScale(); scale.x = newLength; llSetScale(scale); //cancel timer event llSetTimerEvent(0.0); state unconfirmed; } } } timer() { llSay(talk_to_pedestrian, "lostmsg"); } } state unconfirmed { state_entry() { llSetText("unconfirmed:state entry", <0,0,0>,1); //set target events to fire so we know if we're floating off due to the physics engine breaking //targetPos = llGetPos() - (localZDirection() * verticalOffset); targetPos = llGetPos() - <0,0,verticalOffset>; llTarget(targetPos, 1); //set timestamped name timestamp = llGetGMTclock(); llSetObjectName("TMV" + (string)timestamp); //start checking for barriers llSetStatus( STATUS_PHANTOM, TRUE); llSetStatus( STATUS_PHYSICS, TRUE); llSetBuoyancy(1.0); llVolumeDetect(TRUE); //move down llMoveToTarget(targetPos, moveDownDelay); //setup a timer so if no collision events after x seconds we say its clear llSetTimerEvent(allClearTimeout); } not_at_target() { //are we within a reasonable range? if(llVecDist(targetPos, llGetPos()) > maxRangeToTarget) { //tell the pedestrian that its PMV just broke llRegionSay(talk_to_pedestrian, "pmvbroken"); llDie(); } } timer() { //cancel timer - should only fire once llSetTimerEvent(0.0); //no collisions generated so must be... safe(); } collision_start(integer num_detected) { llOwnerSay("num_detected=" + (string)num_detected); //check what object(s) we have collided with integer i; for(i = 0; i < num_detected; i++) { llOwnerSay("llDetectedName(" + (string)i + "=" + llDetectedName(i)); llOwnerSay("llDetectedPos(" + (string)i + "=" + (string)llDetectedPos(i)); //ignore the our pedestrian owner if(llDetectedKey(i) == ownerPedKey) { //ignore it llOwnerSay("ignoring owner"); } else { //is this object a barrier? if(llListFindList(barrierObjectCodes, [llGetSubString(llDetectedName(i), 0, 2)]) != -1) { //if barrier is a timed PMV check timestamp if(llGetSubString(llDetectedName(i), 0, 2) == "TMV") { float rivalTimestamp = (float) llGetSubString(llDetectedName(i), 3, -1); if(timestamp >= rivalTimestamp) { //NOT SAFE: rival TMV got there first! unsafe(); return; } else { //safe so far: rival TMV got there after us - we take priority llOwnerSay("TMV taking priority over rival"); } } else { //NOT SAFE: found at least one barrier inside this PMV volume unsafe(); return; } } } } //no barriers detected so far...keep waiting for timer to expire return; } listen(integer channel, string name, key id, string message) { if(channel == talk_to_pmv) { if(message == "confirm") { //this is a new PMV - update the position and scale llOwnerSay("new PMV got confirm message"); //set "confirmed movement volume" name code llSetObjectName("CMV"); //update position in direction of local positive x-axis by 50% of x-axis scale //this moves the PMV to the volume that will be filled by the pedestrian after it moves vector scale = llGetScale(); llSetPos(llGetPos() + (localXDirection() * (scale.x/2))); //return to volume that represents a person scale.x = 0.25; //default depth llSetScale(scale); state confirmed; } } } } state confirmed { state_entry() { llSetText("confirmed:state entry", <0,0,0>,1); //listen for clear messages from pedestrian llListen(talk_to_pmv, "", NULL_KEY, ""); } listen(integer channel, string name, key id, string message) { if(channel == talk_to_pmv) { if(message == "clear") { //this is an old PMV - get rid of it llOwnerSay("old PMV got clear message"); llDie(); } } } }