Join us in Outworldz at www.outworldz.com:9000 or follow us:

Search dozens of selected web sites for OpenSim and LSL script

New! Script Meta-Search will search thousands of scripts here and at other sites for LSL or Opensim scripts.
Loading

Want to add a script or a project? Upload it and a half million people will see it and your name here this year.

Home   Show All
Category: Contributor: Creator
Train Train_brain  

Train_brain

Train_brain

Category: Train
By : Barney Boomslang
Created: 2010-01-10 Edited: 2010-01-10
Worlds: Second Life

the Zip file

Download all files for Train_brain
Contents are in zip format, with .LSL (text) source code and LSLEdit (text + Solution) formats.
Get file # 1. Train_brain_1.lsl
1 // copyright 2007 Barney Boomslang
2 //
3 // this is under the CC GNU GPL
4 // http://creativecommons.org/licenses/GPL/2.0/
5 //
6 // prim-based builds that just use this code are not seen as derivative
7 // work and so are free to be under whatever license pleases the builder.
8 //
9 // Still this script will be under GPL, so if you build commercial works
10 // based on this script, keep this script open!
11 //
12 // This is the main engine script that is driven by the content of a notecard.
13 // It implements a simple touring language with a very simple command format -
14 // the first character denotes the main command, the second char (optionally)
15 // denotes the subcommand, the rest is parameters. Empty lines are skipped.
16 //
17 // Commands implemented:
18 //
19 // ;<text> this is a comment line and is ignored
20 //
21 // CS<text> say the text on channel 0
22 // CW<text> whisper the text on channel 0
23 // CH<text> shout the text on channel 0
24 //
25 // B<num> sets the announcement channel to <num>
26 // AR<text> announces (llRegionSay) <text> on channel <num> (see B command)
27 // AS<text> say <text> on channel <num> (see B command)
28 // AW<text> whisper <text> on channel <num> (see B command)
29 // AH<text> shout <text> on channel <num> (see B command)
30 //
31 // D<text> waits for an announcement of <text> on the channel set with B
32 //
33 // L<num>,<text> link message with the number <num> and text <text>
34 // L<text> link message with the text <text> and number 0
35 //
36 // T<num> wait the given number of seconds
37 //
38 // S<num> set the "speed" of steps - how large a single step is
39 // P<coord> move to <coord> in steps of size <speed> (see S command)
40 // W<coord> warp to <coord> in one big hop
41 // Z<coord> zoom to <coord> (zooming is llSetPos in a tight loop)
42 // R<rel-coord> move to <current-pos> + <rel-coord> in <speed> sized steps
43 //
44 // Xdie kill the running object
45 // Xrestart restart the running notecard
46
47 string notecard = "";
48 integer nLine = 0;
49 key qLine = NULL_KEY;
50
51 integer channel = -324543; // the channel to operate on for announcements
52 integer trace = -65432; // the channel to announce positions on
53
54 float speed = 1.0; // speed is the size of steps for normal movement
55 float slack = 0.2; // slack is the allowed distance on the last step
56
57 vector AXIS_UP = <0,0,1>;
58 vector AXIS_LEFT = <0,1,0>;
59 vector AXIS_FWD = <1,0,0>;
60
61 vector base_rot = <180,0,180>;
62 vector after_rot = <270,0,0>;
63
64 // variables for the automatic rezzing of cars
65 vector offset = <0,0,0.434>; // direct offset to the current position of the engine
66 float distance = 7.0; // distance to move the engine after rezzing one car
67
68 // what we are waiting for when D executes
69 string waitForString;
70
71 // a timeout for notecard reading - if the line doesn't arrive in time, the train will derez
72 float tourtimeout = 180.0; // this is in seconds
73
74 // a timeout counter for the default state
75 integer waitcount;
76
77 // rez the named object at the current position plus offset with current rotation
78 rezit(string name, integer channel)
79 {
80 vector dir = llRot2Fwd(llGetRot());
81 vector pos = llGetPos()+offset+dir*distance;
82 llRezAtRoot(name, pos, ZERO_VECTOR, llGetRot(), channel);
83 }
84
85 // move the engine the predefined distance in the current direction
86 movit()
87 {
88 vector dir = llRot2Fwd(llGetRot());
89 vector pos = llGetPos()-dir*distance;
90 llSetPos(pos);
91 }
92
93
94 // jump to a target in one big swipe
95 llWarp2Pos( vector d, rotation rot )
96 {
97 if( d.z > 768 )
98 d.z = 768;
99 integer s = (integer)(llVecMag(d-llGetPos())/10)+1;
100 if( s > 100 )
101 s = 100;
102 integer e = (integer)( llLog( s ) / llLog( 2 ) );
103 list rules = [ PRIM_POSITION, d ];
104 integer i;
105 for ( i = 0 ; i < e ; ++i )
106 rules += rules;
107 integer r = s - (integer)llPow( 2, e );
108 if( r > 0 )
109 rules += llList2List( rules, 0, r * 2 + 1 );
110 llSetPrimitiveParams( [ PRIM_ROTATION, rot ] + rules );
112 }
113
114 // tight moving loop ("zooming")
115 moveto(vector dest, rotation r)
116 {
117 list l = [ PRIM_ROTATION, r, PRIM_POSITION, dest ];
118 while(llVecDist(llGetPos(), dest) > 9)
119 {
122 }
123 if(llVecDist(llGetPos(), dest) > slack)
124 {
125 llSetPos(dest);
127 }
128 }
129
130 // loose moving loop - moving in defined steps
131 movetostepped(vector dest, rotation r)
132 {
133 integer first = TRUE;
134 vector pos = llGetPos();
135 vector step = llVecNorm(dest - llGetPos()) * speed;
136 while(llVecDist(pos, dest) > speed)
137 {
138 pos += step;
139 if(first)
140 {
143 }
144 else
145 {
146 llSetPos(pos);
148 }
149 }
150 if(llVecDist(pos, dest) > slack)
151 {
152 llSetPos(dest);
154 }
155 }
156
157 // simple function to calculate the needed rotation to point a given axis at a target
158 rotation getRotToPointAxisAt(rotation root, vector axis, vector target) {
159 return root * llRotBetween(axis * root, target - llGetPos());
160 }
161
162 // calculate the "prime" (left/right and up/down) rotations to point at a target
163 rotation getPrimeRotation(vector dest)
164 {
165 vector p1 = llGetPos();
166 rotation brot = llEuler2Rot(base_rot*DEG_TO_RAD);
167 // calculate left/right rotation
168 vector p2 = dest;
169 p2.z = p1.z;
170 rotation rleft = getRotToPointAxisAt(brot, AXIS_FWD, p2);
171 vector r2 = llRot2Euler(rleft);
172 r2.x = 0;
173 r2.y = 0;
174 rleft = llEuler2Rot(r2);
175 // calculate up/down rotation
176 p2 = dest;
177 p2.x = p1.x + llVecDist(p1, dest);
178 p2.y = p1.y;
179 rotation rup = getRotToPointAxisAt(brot, AXIS_FWD, p2);
180 r2 = llRot2Euler(rup);
181 r2.x = 0;
182 r2.z = 0;
183 rup = llEuler2Rot(r2);
184 // return combined rotations
185 return llEuler2Rot(after_rot*DEG_TO_RAD) * rup * rleft * brot;
186 }
187
188 // this state waits for a notecard to be dropped into inventory to start
189 // the tour. Before starting it, it will decide on the comms channel and will
190 // rez the actual cars of the train.
191 default
192 {
194 {
195 waitcount = 0;
196 speed = 1.0;
197 slack = 0.2;
198 llSetTimerEvent(10.0);
199 }
200
202 {
203 // create a random trace channel for the engine->car communication
204 trace = (integer)(-1*(llFrand(100000) + 100000));
205 // rez the cars (this needs to be copied from the rez cars script)
206 // and adapted to one-car rezzing or two-car rezzing (depending on inventory)
208 {
209 rezit("car", trace-1);
210 movit();
211 rezit("car", trace);
212 }
213 else
214 {
215 rezit("car2", trace-1);
216 movit();
217 rezit("car1", trace);
218 }
219 }
220
221 on_rez(integer param)
222 {
224 }
225
226 changed(integer change)
227 {
228 if(change & CHANGED_INVENTORY)
229 {
231 {
233 nLine = 0;
234 state running;
235 }
236 }
237 }
238
239 timer()
240 {
242 {
244 nLine = 0;
245 state running;
246 }
247 waitcount++;
248 if(waitcount > 30)
249 {
250 llSay(0, "Sorry, there are problems with the grid, this tour is canceled!");
251 llDie();
252 }
253 }
254 }
255
256 // this state is the actually running state for the engine
257 state running
258 {
260 {
261 qLine = llGetNotecardLine(notecard, nLine);
262 llSetTimerEvent(tourtimeout);
263 }
264
265 on_rez(integer start_param)
266 {
268 }
269
270 timer()
271 {
272 // emergency shutdown of the train in case of notecard timeouts
273 llSay(0, "Sorry, there are problems with the grid, this tour is canceled!");
274 llShout(trace, "!DIE!");
275 llDie();
276 }
277
278 dataserver(key id, string data)
279 {
280 if(id == qLine)
281 {
282 if(data != EOF)
283 {
284 llSetTimerEvent(0.0);
285 string cmd = llGetSubString(data, 0, 0);
286 string parm = llGetSubString(data, 1, -1);
287 if(cmd == "C")
288 {
289 string range = llGetSubString(parm, 0, 0);
290 parm = llGetSubString(parm, 1, -1);
291 if(range == "S")
292 {
293 llSay(0, parm);
294 }
295 else if(range == "W")
296 {
297 llWhisper(0, parm);
298 }
299 else if(range == "H")
300 {
301 llShout(0, parm);
302 }
303 else
304 {
305 llOwnerSay("bad chat range: " + range);
306 }
307 }
308 else if(cmd == "B")
309 {
310 channel = (integer)parm;
311 }
312 else if(cmd == "A")
313 {
314 string range = llGetSubString(parm, 0, 0);
315 parm = llGetSubString(parm, 1, -1);
316 if(range == "S")
317 {
318 llSay(channel, parm);
319 }
320 else if(range == "W")
321 {
322 llWhisper(channel, parm);
323 }
324 else if(range == "H")
325 {
326 llShout(channel, parm);
327 }
328 else if(range == "R")
329 {
330 llRegionSay(channel, parm);
331 }
332 else
333 {
334 llOwnerSay("bad chat range: " + range);
335 }
336 }
337 else if(cmd == "L")
338 {
339 integer p = llSubStringIndex(parm, ",");
340 if(p >= 0)
341 {
342 integer num = (integer)llGetSubString(parm,0,p-1);
343 string str = llGetSubString(parm,p+1,-1);
345 }
346 else
347 {
349 }
350 }
351 else if(cmd == "T")
352 {
353 llSleep((float)parm);
354 }
355 else if(cmd == "S")
356 {
357 speed = (float)parm;
358 slack = speed / 5.0;
359 }
360 else if((cmd == "R") ||\xA0(cmd == "P") || (cmd == "W") ||\xA0(cmd == "Z"))
361 {
362 vector p1 = llGetPos();
363 vector p2 = (vector)parm;
364 if(cmd == "R")
365 {
366 p2 = llGetPos() + p2;
367 }
368 if(p2 != ZERO_VECTOR)
369 {
370 rotation r = getPrimeRotation(p2);
371 if((cmd == "P") || (cmd == "R"))
372 {
373 movetostepped(p2, r);
374 }
375 else if(cmd == "Z")
376 {
377 moveto(p2, r);
378 }
379 else if(cmd == "W")
380 {
381 llWarp2Pos(p2, r);
382 }
383 }
384 else
385 {
386 llOwnerSay("bad vector: " + parm);
387 }
388 }
389 else if(cmd == "X")
390 {
391 if(parm == "die")
392 {
393 // propagate the die to the cars
394 llShout(trace, "!DIE!");
395 llDie();
396 }
397 else if(parm == "restart")
398 {
399 nLine = -1;
400 }
401 }
402 else if(cmd == "D")
403 {
404 waitForString = parm;
405 state waiting;
406 }
407 else
408 {
409 if((cmd != "") && (cmd != ";"))
410 {
411 llOwnerSay("bad command: " + cmd + "(" + parm + ")");
412 }
413 }
414 ++nLine;
415 qLine = llGetNotecardLine(notecard, nLine);
416 llSetTimerEvent(tourtimeout);
417 }
418 else
419 {
420 llRemoveInventory(notecard);
421 state paused;
422 }
423 }
424 }
425 }
426
427 // this is the state for the D command - it just waits for a string on the broadcast channel
428 state waiting
429 {
431 {
432 llListen(channel, "", NULL_KEY, waitForString);
433 llSetTimerEvent(60.0);
434 }
435
437 {
438 // on receiving the expected line, we just jump back to the next line in the notecard
439 ++nLine;
440 }
441
442 listen(integer chan, string name, key id, string message)
443 {
444 if(chan == channel)
445 {
446 // if we got the broadcast we wait for, continue script
447 state running;
448 }
449 }
450
451 timer()
452 {
453 // this keeps the cars around as long as the engine lives and sends beacons
454 llShout(trace, "!NOP!");
455 }
456 }
457
458 // this state is used at the end of a tour that doesn't end with Xdie. It will just
459 // wait for a new notecard and while doing so, will send "!NOP!" just like a D command.
460 state paused
461 {
463 {
464 llSetTimerEvent(60.0);
465 }
466
467 on_rez(integer start_param)
468 {
470 }
471
472 changed(integer change)
473 {
474 if(change & CHANGED_INVENTORY)
475 {
477 {
479 nLine = 0;
480 state running;
481 }
482 }
483 }
484
485 timer()
486 {
487 // this keeps the cars around as long as the engine lives and sends beacons
488 llShout(trace, "!NOP!");
489 }
490 }

Back to the Best Free Tools in Second Life and OpenSim.