integer channel = -94531; integer report_channel = -94530; integer direction; integer curPoint; list points; string route; integer nextStation =-1; integer isPaused; float OFFSET=0; float SPEED = 3.75; //meters /second vector INITROTATION=<0,0,PI/2>; float WATERHEIGHT = 20.05; list messages; list delays; list messageTimes; integer curMessage; beginRoute(list points) { llSetKeyframedMotion( [], []); //llSetRot(ZERO_ROTATION); llSleep(0.3); messageTimes = []; curMessage = 0; OFFSET=(float)llGetObjectDesc(); vector pos = llList2Vector(points,0); llSetRegionPos(pos); llSetRot(llEuler2Rot(INITROTATION)); rotation rot = llEuler2Rot(INITROTATION); integer i; list kf; float totTime =0; messageTimes = []; for (i=0; i < llGetListLength(points); i++) { vector v = llList2Vector(points, i); rotation r2 = llEuler2Rot(INITROTATION); if (i < llGetListLength(points)-1) { vector vn = llVecNorm(llList2Vector(points, i+1) - v); // break rotation in 2 parts: along Z, then along the rest. llRotBetween would turn the train upside-down vector v2 = vn; v2.z =0; rotation r2a = llRotBetween(<1,0,0>, v2); // Rotation along the Z axis only rotation r2b = llRotBetween(<1,0,0>*r2a, vn); r2 = r2a*r2b; //llRotBetween(<1,0,0>,vn); } else { r2 = rot; //v.y -= OFFSET; // boat Parking offset } vector cor = llRot2Euler(r2); if (cor.x == -PI) cor.x = PI; //cor.x=0; // Remove any rotation around X r2 = llEuler2Rot(cor); float t; if (i>0) { kf += (1.0)*(v-pos); kf += ZERO_ROTATION; t = llVecMag(v-pos)/SPEED; //adjust for speed kf += t*(1.0); rotation myrot = llRotBetween(<1,0,0>*rot, <1,0,0>*r2); kf += ZERO_VECTOR ; kf += r2 / rot; // myrot; //llEuler2Rot(<0,cor.y,0>); kf += .5; } else // the zero-th frame is just a rotation { kf += ZERO_VECTOR; kf += (r2/rot); kf += 2; //adjust for speed t = 2; } kf += ZERO_VECTOR; kf += ZERO_ROTATION; float delay = llList2Float(delays, i); kf += delay; //adjust for speed t += delay; totTime+= t; pos = v; rot = r2; messageTimes += (t+1 ); } //llLoopSound("paddle", 1.0); llSetKeyframedMotion( kf, [KFM_DATA, KFM_TRANSLATION|KFM_ROTATION, KFM_MODE, KFM_LOOP]); llMessageLinked(LINK_SET, 0, "START", ""); llStopSound(); llSleep(.1); llLoopSound("train", 1.); } doStop() { isPaused = !isPaused; if (isPaused) llSetKeyframedMotion( [], [KFM_COMMAND, KFM_CMD_PAUSE]); else llSetKeyframedMotion( [], [KFM_COMMAND, KFM_CMD_PLAY]); if (isPaused) { llMessageLinked(LINK_SET, 0, "STOP", ""); llStopSound(); } else { llMessageLinked(LINK_SET, 0, "START", ""); llLoopSound("train", 1.); } } default { state_entry() { llSitTarget(ZERO_VECTOR, ZERO_ROTATION); llListen(channel,"", "",""); llMessageLinked(LINK_SET, 0, "STOP", ""); } listen(integer chan, string n, key sender, string cmd) { if (cmd == "Pause/Cont") { doStop(); } else if (cmd == "PANIC") { llSetKeyframedMotion([], []); llStopSound(); llSetTimerEvent(0); } else if (cmd == "Reset11") { list lines = llParseString2List(osGetNotecard("route"), ["\n"], []); integer j=0; { list tk = llParseString2List(llList2String(lines,j), ["|"], []); vector p= llList2Vector(tk,0); // llSay( 0, (string)p); llSetRegionPos(p); llSetRot( llEuler2Rot(INITROTATION)); } } else if (cmd == "Reset") { list lines = llParseString2List(osGetNotecard("route"), ["\n"], []); integer j; points = []; delays = []; messages = []; for (j=0; j < llGetListLength(lines); j++) { list tk = llParseString2List(llList2String(lines,j), ["|"], []); points += llList2Vector(tk,0); delays += llList2Float(tk,1); messages += llList2String(tk,2); } beginRoute(points); llSetTimerEvent(5); } } touch_start(integer n) { if (llDetectedKey(0) == llGetOwner()) llDialog(llDetectedKey(0), "Select", ["Reset", "Pause/Cont", "PANIC", "CLOSE"], channel); } changed(integer change) { if (change & CHANGED_LINK) { integer i; for (i=2; i < llGetNumberOfPrims(); i++) if (llAvatarOnLinkSitTarget(i) != NULL_KEY) // llGetNumberOfPrims() > llGetObjectPrimCount(llGetKey())) { // llSetTimerEvent(2); // llOwnerSay("Seated"); return; } { //else // llSetTimerEvent(0); } } } timer() { integer i; for ( i=0; i < llGetListLength(points); i++) { if (llVecDist(llGetPos(), llList2Vector(points,i))< 7) { // llOwnerSay("PT = "+i); if (i != nextStation) { string s = llList2String(messages, i); if (s != "") { llWhisper(0 , "/me <<" +s+ ">>"); llTriggerSound("dingdong", 1.0); llWhisper(report_channel, "1>"+s); } nextStation = i; return; } } } } }