//*************************************************************** // 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"]; float allClearTimeout = 12; //seconds float moveDownDelay = 4; //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); //llOwnerSay("PMV" + (string)llGetKey() + ":default:state_entry()"); llSetColor(<0,0,1>, ALL_SIDES); //llOwnerSay("state entry"); } on_rez(integer start_param) { llSetText("default:on_rez",<0,0,0>, 1); //llOwnerSay("PMV" + (string)llGetKey() + ":onrez"); 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("PMV" + (string)llGetKey() + ":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("PMV" + (string)llGetKey() + ":got msg:" + message); if(channel == talk_to_pmv) { if(llGetSubString(message, 0, 2) == "ln:") { //save owner ped key from message - so we can ignore it later when detecting collisions ownerPedKey = id; //scale to correct size float newLength = (float)llGetSubString(message, 3, -1); vector scale = llGetScale(); scale.x = newLength; llSetScale(scale); state unconfirmed; } } } timer() { //llOwnerSay("PMV" + (string)llGetKey() + ":telling ped about lostmsg"); llSay(talk_to_pedestrian, "lostmsg"); } } state unconfirmed { state_entry() { llSetText("unconfirmed:state_entry",<0,0,0>, 1); //llOwnerSay("PMV" + (string)llGetKey() + ":unconfirmed:state_entry"); //set target events to fire so we know if we're floating off due to the physics engine breaking targetPos = llGetPos() - (localZDirection() * 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(llGetPos() - (localZDirection() * verticalOffset), 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? //llOwnerSay("PMV" + (string)llGetKey() + ":not_at_target"); if(llVecDist(targetPos, llGetPos()) > maxRangeToTarget) { //llOwnerSay("PMV" + (string)llGetKey() + ":pmv broken"); //tell the pedestrian that its PMV just broke llRegionSay(talk_to_pedestrian, "pmvbroken"); llDie(); } } timer() { //llOwnerSay("PMV" + (string)llGetKey() + ":timer expired... safe"); //cancel timer - should only fire once llSetTimerEvent(0.0); //no collisions generated so must be... safe(); } collision_start(integer num_detected) { //llOwnerSay("PMV" + (string)llGetKey() + ":checking collisions"); //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 an avatar? integer vBitType = llDetectedType(i); if(1 & vBitType) { //don't crash into avatars unsafe(); return; } 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! //llOwnerSay("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 //llOwnerSay("not safe - barrier"); unsafe(); return; } } } } } //no barriers detected so far...keep waiting for timer to expire return; } listen(integer channel, string name, key id, string message) { //llOwnerSay("PMV" + (string)llGetKey() + ":got msg:" + 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); //llOwnerSay("PMV" + (string)llGetKey() + ":confirmed:state_entry"); //listen for clear messages from pedestrian llListen(talk_to_pmv, "", NULL_KEY, ""); } listen(integer channel, string name, key id, string message) { //llOwnerSay("PMV" + (string)llGetKey() + ":got msg:" + 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(); } } } }